ProtoEncoder框架代码

Signed-off-by:wenlong12 <wenlong12@huawei.com>

Signed-off-by: wenlong12 <wenlong12@huawei.com>
This commit is contained in:
wenlong12 2023-04-23 11:51:42 +08:00
parent 5b3b29d6ae
commit 901b54cb8e
18 changed files with 3558 additions and 5 deletions

View File

@ -21,6 +21,9 @@ OHOS_X64_OUT=$PROJECT_TOP/$2/
LIBCXX_X64_OUT=$PROJECT_TOP/$1/ndk/libcxx/linux_x86_64
SUBSYS_X64_OUT=$PROJECT_TOP/$2/developtools/profiler
PROTOC=$PROJECT_TOP/$2/developtools/profiler/protoc
OPT_PLUGIN_PATH=$PROJECT_TOP/$2/developtools/profiler/protoencoder_plugin
OPT_PLUGIN=--plugin=protoc-gen-opt=$PROJECT_TOP/$2/developtools/profiler/protoencoder_plugin
OPT_OUT=--opt_out
PYTHON_SHELL=$THIS_DIR/make_standard_proto.py # shell path
TMP=$2
PROTO_OUT_DIR="$PROJECT_TOP/${TMP%/*}/$3" # path of the new proto file
@ -56,5 +59,14 @@ do
done
PARAMS_ALL="$PARAMS_SRC $PARAMS_STANDARD" # add new argument list to old argument list
# avoid conflict, param4=--plugin* means ipc plugin, generate encode file if opt plugin exist
if [[ "$4" != --plugin* ]]; then
if [ -f "$OPT_PLUGIN_PATH" ]; then
echo "generate protobuf optimize code OPT_PLUGIN = $OPT_PLUGIN"
echo "optimize EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $OPT_PLUGIN $OPT_OUT $5 $PARAMS_ALL"
LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $OPT_PLUGIN $OPT_OUT $5 $PARAMS_ALL
fi
fi
echo "EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $PARAMS_ALL"
LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $PARAMS_ALL

View File

@ -82,7 +82,8 @@
"//developtools/profiler/device:fuzztest",
"//developtools/profiler/device:unittest",
"//developtools/profiler/interfaces/kits/test:unittest",
"//developtools/profiler/hidebug/test/unittest:unittest"
"//developtools/profiler/hidebug/test/unittest:unittest",
"//developtools/profiler/proto_encoder/test:unittest"
]
}
}

View File

@ -38,7 +38,7 @@ const WriterStruct* WriterAdapter::GetStruct()
return &writerStruct_;
}
long WriterAdapter::WriteFunc(WriterStruct* writer, const void* data, size_t size)
long WriterAdapter::WriteFunc(WriterStruct* writer, const char* data, size_t size)
{
static_assert(offsetof(WriterAdapter, writerStruct_) == 0, "unexpected alignment of writerStruct_!");
WriterAdapter* writerAdaptor = reinterpret_cast<WriterAdapter*>(writer); // 转成 WriterAdapter*

View File

@ -31,7 +31,7 @@ public:
WriterPtr GetWriter();
private:
static long WriteFunc(WriterStruct* writer, const void* data, size_t size);
static long WriteFunc(WriterStruct* writer, const char* data, size_t size);
static bool FlushFunc(WriterStruct* writer);
private:

View File

@ -69,3 +69,24 @@ ohos_executable("protoc_gen_ipc") {
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
part_name = "${OHOS_PROFILER_PART_NAME}"
}
ohos_executable("protoencoder_plugin") {
sources = [
"src/proto_encoder_plugin.cpp",
"src/proto_encoder_plugin_generator.cpp",
]
include_dirs = [
"include",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}",
]
public_configs = [ "${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config" ]
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib(${host_toolchain})",
]
install_enable = false
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
part_name = "${OHOS_PROFILER_PART_NAME}"
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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.
*/
#ifndef PROTO_ENCODER_GENERATOR_H
#define PROTO_ENCODER_GENERATOR_H
#include <map>
#include <string>
#include <vector>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include <google/protobuf/io/printer.h>
class ProtoEncoderGenerator : public google::protobuf::compiler::CodeGenerator {
public:
ProtoEncoderGenerator();
~ProtoEncoderGenerator();
bool Generate(const google::protobuf::FileDescriptor* file,
const std::string& parameter,
google::protobuf::compiler::GeneratorContext* context,
std::string* error) const override;
};
#endif

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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 <iostream>
#include "proto_encoder_plugin_generator.h"
int main(int argc, char* argv[])
{
ProtoEncoderGenerator generator;
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

View File

@ -0,0 +1,409 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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 "proto_encoder_plugin_generator.h"
using google::protobuf::FileDescriptor;
using google::protobuf::EnumDescriptor;
using google::protobuf::Descriptor;
using google::protobuf::io::Printer;
using google::protobuf::EnumValueDescriptor;
using google::protobuf::FieldDescriptor;
class OptGeneratorImpl {
public:
explicit OptGeneratorImpl(const FileDescriptor* file) : fileContent_(file), printer_(nullptr) {}
std::string GetPrefix(std::string fileName)
{
std::string prefix = "";
for (size_t i = 0; i < fileName.length(); i++) {
if (fileName.c_str()[i] == '.') {
break;
}
prefix += fileName.c_str()[i];
}
return prefix;
}
std::string SetNames(std::string fileName, std::string packageName)
{
fileName_ = fileName;
packageName_ = packageName + "::";
headFileName_ = "";
for (size_t i = 0; i < fileName.length(); i++) {
if (fileName.c_str()[i] == '.') {
break;
}
headFileName_ += fileName.c_str()[i];
}
baseName_ = SwapName(headFileName_);
return headFileName_;
}
std::string SwapName(std::string s)
{
std::string ret = "";
bool b = true;
for (size_t i = 0; i < s.length(); i++) {
char c = s[i];
if (c == '_') {
b = true;
} else if (b && c >= 'a' && c <= 'z') {
ret += (c + 'A' - 'a');
b = false;
} else {
ret += c;
}
}
return ret;
}
std::string Tolowercase(const std::string& s)
{
std::string str = s;
std::transform(str.begin(), str.end(), str.begin(), [](char& c) {
return std::tolower(c);
});
return str;
}
void GenHeader()
{
GenPrefix();
GenerateEnum();
GenerateClass();
GenSurfix();
}
void GenPrefix()
{
printer_->Print("// Generated by protoencoder plugin.\n");
printer_->Print("#pragma once\n");
printer_->Print("#include \"base_message.h\"\n");
for (int i = 0; i < fileContent_->dependency_count(); ++i) {
printer_->Print("#include \"@name@.pbencoder.h\"\n", "name",
GetPrefix(fileContent_->dependency(i)->name()));
}
printer_->Print("namespace OHOS {\n");
printer_->Print("namespace Developtools {\n");
printer_->Print("namespace Profiler {\n");
printer_->Print("namespace ProtoEncoder {\n");
}
void GenerateEnum()
{
for (int i = 0; i < fileContent_->enum_type_count(); ++i) {
printer_->Print("enum @class@ : uint32_t {\n", "class", fileContent_->enum_type(i)->name());
printer_->Indent();
for (int j = 0; j < fileContent_->enum_type(i)->value_count(); ++j) {
const EnumValueDescriptor* value = fileContent_->enum_type(i)->value(j);
const std::string value_name = value->name();
printer_->Print("@name@ = @number@,\n", "name", value_name, "number",
std::to_string(value->number()));
}
printer_->Outdent();
printer_->Print("};\n");
}
}
void GenerateClass()
{
// forward declaration
for (int i = 0; i < fileContent_->message_type_count(); ++i) {
const Descriptor* message = fileContent_->message_type(i);
printer_->Print("class @name@;\n", "name", message->name());
}
for (int i = 0; i < fileContent_->message_type_count(); ++i) {
const Descriptor* message = fileContent_->message_type(i);
for (int j = 0; j < message->nested_type_count(); ++j) {
const Descriptor* nestmessage = message->nested_type(j);
printer_->Print(
"class @name@ : public BaseMessage {\n"
" public:\n",
"name", nestmessage->name());
printer_->Indent();
printer_->Print("@name@() = default;\n", "name", nestmessage->name());
printer_->Print(
"explicit @name@(RandomWriteCtx* writeCtx, MessageStack* subMessageStack = nullptr) : BaseMessage(writeCtx, subMessageStack) {}\n",
"name", nestmessage->name());
GenerateFieldsID(nestmessage);
GenerateFunction(nestmessage);
printer_->Outdent();
printer_->Print("};\n\n");
}
printer_->Print(
"class @name@ : public BaseMessage {\n"
" public:\n",
"name", message->name());
printer_->Indent();
printer_->Print("@name@() = default;\n", "name", message->name());
printer_->Print(
"explicit @name@(RandomWriteCtx* writeCtx, MessageStack* subMessageStack = nullptr) : BaseMessage(writeCtx, subMessageStack) {}\n",
"name", message->name());
GenerateFieldsID(message);
GenerateFunction(message);
printer_->Outdent();
printer_->Print("};\n\n");
}
}
void GenerateFieldsID(const Descriptor* message)
{
for (int i = 0; i < message->field_count(); ++i) {
const FieldDescriptor* field = message->field(i);
printer_->Print("static const uint32_t FIELDID_@name@ = @id@;\n",
"name", field->name(), "id", std::to_string(field->number()));
}
}
void GenerateFunction(const Descriptor* message)
{
// field->is_repeated()
for (int i = 0; i < message->field_count(); ++i) {
const FieldDescriptor* field = message->field(i);
if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
printer_->Print("inline @typename@* @mora@_@name@()\n",
"mora", field->is_repeated()?"add":"mutable",
"typename", field->message_type()->name(),
"name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("return AddSubMessage<@typename@>(FIELDID_@name@);\n",
"typename", field->message_type()->name(),
"name", field->name());
printer_->Outdent();
printer_->Print("}\n");
} else if (field->type() == FieldDescriptor::TYPE_BYTES) {
printer_->Print("inline void set_@name@(const void* bytes, uint32_t size)\n",
"name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("AddBytes(FIELDID_@name@, bytes, size);\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("void set_@name@(GetDataCallback getData)\n", "name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("return AddBytesByCallBack(FIELDID_@name@, getData);\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("inline RandomWriteCtx* startAdd_@name@()\n", "name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("return StartAddBytes(FIELDID_@name@);\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("inline void finishAdd_@name@(int32_t size)\n", "name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("return FinishAddBytes(size);\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
} else if (field->type() == FieldDescriptor::TYPE_STRING) {
printer_->Print("inline void @sora@_@name@(const std::string& str)\n",
"sora", field->is_repeated()?"add":"set",
"name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("inline void @sora@_@name@(std::string&& str)\n",
"sora", field->is_repeated()?"add":"set",
"name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("inline void @sora@_@name@(const char* str)\n",
"sora", field->is_repeated()?"add":"set",
"name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("AddBytes(FIELDID_@name@, str, strlen(str));\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("inline void @sora@_@name@(const char* str, uint32_t len)\n",
"sora", field->is_repeated()?"add":"set",
"name", Tolowercase(field->name()));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("AddBytes(FIELDID_@name@, str, len);\n", "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
} else {
// varint, fix32, fix64
printer_->Print("inline void @sora@_@name@(@paramtype@ v)\n",
"sora", field->is_repeated()?"add":"set", "name", Tolowercase(field->name()),
"paramtype", GetParamType(field));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("@type@(FIELDID_@name@, v);\n", "type",
GetInnerType(field), "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
// packed
if (!field->is_repeated()) {
continue;
}
if (field->type() == FieldDescriptor::TYPE_SINT32 ||
field->type() == FieldDescriptor::TYPE_SINT64) {
perror("repeated signed(zigzag) fields are not supported in libprotobuf\n");
continue;
}
if (!field->is_packed()) {
continue;
}
printer_->Print("inline void add_@name@(const @paramtype@* array, uint32_t size)\n",
"name", Tolowercase(field->name()),
"paramtype", GetParamType(field));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("@type@(FIELDID_@name@, array, size);\n",
"type", GetInnerType(field, true), "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
printer_->Print("inline void add_@name@(const std::vector<@paramtype@>& array)\n",
"name", Tolowercase(field->name()),
"paramtype", GetParamType(field));
printer_->Print("{\n");
printer_->Indent();
printer_->Print("@type@(FIELDID_@name@, array.data(), array.size());\n",
"type", GetInnerType(field, true), "name", field->name());
printer_->Outdent();
printer_->Print("}\n");
}
}
}
std::string GetParamType(const FieldDescriptor* field)
{
switch (field->type()) {
case FieldDescriptor::TYPE_BOOL:
return "bool";
case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_FIXED32:
return "uint32_t";
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SFIXED32:
return "int32_t";
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SFIXED64:
return "int64_t";
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_FIXED64:
return "uint64_t";
case FieldDescriptor::TYPE_DOUBLE:
return "double";
case FieldDescriptor::TYPE_FLOAT:
return "float";
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_BYTES:
return "";
default:
return "";
}
return "";
}
std::string GetInnerType(const FieldDescriptor* field, bool packed = false)
{
switch (field->type()) {
case FieldDescriptor::TYPE_BOOL:
case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_UINT64:
return packed?"AddPackedVarint":"AddVarint";
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
return "AddZigZagVarint";
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_DOUBLE:
return packed?"AddPackedFixed":"AddFixed64";
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_FLOAT:
return packed?"AddPackedFixed":"AddFixed32";
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_BYTES:
return "";
}
return "";
}
void CollectContext()
{
return;
}
void GenSurfix()
{
printer_->Print("} // namespace ProtoEncoder\n");
printer_->Print("} // namespace Profiler\n");
printer_->Print("} // namespace Developtools\n");
printer_->Print("} // namespace OHOS\n");
}
void SetPrinter(Printer* stub_h_printer)
{
printer_ = stub_h_printer;
}
private:
std::string fileName_ = "";
std::string baseName_ = "";
std::string packageName_ = "";
std::string headFileName_ = "";
//std::string header_ = "";
std::vector<std::string> namespaces_;
const FileDescriptor* const fileContent_;
std::vector<const Descriptor*> stack;
std::vector<const EnumDescriptor*> enums_;
Printer* printer_;
};
ProtoEncoderGenerator::ProtoEncoderGenerator() {}
ProtoEncoderGenerator::~ProtoEncoderGenerator() {}
bool ProtoEncoderGenerator::Generate(const google::protobuf::FileDescriptor* file,
const std::string& parameter,
google::protobuf::compiler::GeneratorContext* context,
std::string* error) const
{
auto pcsp = std::make_shared<OptGeneratorImpl>(file);
std::string base_name = pcsp->SetNames(file->name(), file->package());
std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> header_output(context->Open(base_name +
".pbencoder.h"));
std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> source_output(context->Open(base_name +
".pbencoder.cc"));
Printer h_printer(header_output.get(), '@');
pcsp->SetPrinter(&h_printer);
pcsp->GenHeader();
Printer cc_printer(source_output.get(), '@');
cc_printer.Print("// empty\n");
return true;
}

View File

@ -58,6 +58,49 @@ typedef int (*PluginSessionStartCallback)(const uint8_t* configData, uint32_t co
*/
typedef int (*PluginReportResultCallback)(uint8_t* bufferData, uint32_t bufferSize);
typedef struct RandomWriteCtx RandomWriteCtx;
/**
* @brief get memory of the specified length
* @param size : The byte counts to be used
* @param memory : output current target memory pointer
* @param offset : output current offset relative to the head of writing
* @return : Return true for success and false for failure
*/
typedef bool (*GetMemoryFunc)(RandomWriteCtx* ctx, uint32_t size, uint8_t** memory, uint32_t* offset);
/**
* @brief seek to the specified offset for writing
* @param offset : offset relative to the head of writing
* @return : Return true for success and false for failure
*/
typedef bool (*SeekFunc)(RandomWriteCtx* ctx, uint32_t offset);
/**
* RandomWriteCtx : type definition, random write context.
*/
struct RandomWriteCtx {
/**
* get the memory and current offset.
*/
GetMemoryFunc getMemory;
/**
* seek for writing.
*/
SeekFunc seek;
};
/**
* @brief interface type of Plugin result reporting interface type
* The plugin reports the bytes data by randomWrite() directly,
* or constructor proto_encoder message by randomWrite(),
* the message class code is generated by protoc using proto file.
* @param randomWrite: random write context
* @return size that has been reproted, -1 when reprot faild.
*/
typedef int32_t (*PluginReportResultOptimizeCallback)(RandomWriteCtx* randomWrite);
/**
* @brief interface type of plugin session stop,
* Called when stopping plugin sessions
@ -84,7 +127,7 @@ typedef struct WriterStruct WriterStruct;
* @param size : The byte counts in the data buffer
* @return : Return the number of bytes written for success, and returns -1 for failure
*/
typedef long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size);
typedef long (*WriteFuncPtr)(WriterStruct* writer, const char* data, size_t size);
/**
* @brief flush : interface type
@ -93,7 +136,23 @@ typedef long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size
typedef bool (*FlushFuncPtr)(WriterStruct* writer);
/**
* WriterStruct : type definition, containing two function pointers.
* @brief StartReport interface type
* @return : Return RandomWriteCtx for success, null for failure
* The plugin reports the bytes data by RandomWriteCtx directly,
* or constructor proto_encoder message by RandomWriteCtx,
* the message class code is generated by protoc using proto file.
*/
typedef RandomWriteCtx* (*StartReportFuncPtr)(WriterStruct* writer);
/**
* @brief FinishReport interface type
* @param size : The byte counts of data reported
* @return
*/
typedef void (*FinishReportFuncPtr)(WriterStruct* writer, int32_t size);
/**
* WriterStruct : type definition.
*/
struct WriterStruct {
/**
@ -105,6 +164,21 @@ struct WriterStruct {
* flush function pointer,point to the actual flush function.
*/
FlushFuncPtr flush;
/**
* startMessage function pointer, point to the actual startMessage function.
*/
StartReportFuncPtr startReport;
/**
* finishMessage function pointer, point to the actual finishMessage function.
*/
FinishReportFuncPtr finishReport;
/**
* data encoding method, true is protobuf, false is protoencoder, default is true for UT.
*/
bool protobufSerialize = true;
};
/**
@ -149,6 +223,12 @@ struct PluginModuleCallbacks {
* report plugin basic data
*/
PluginReportBasicDataCallback onReportBasicDataCallback = 0;
/**
* Data reporting callback optimized and it is used to connect the
* polling reporting results of plugin management framework.
*/
PluginReportResultOptimizeCallback onPluginReportResultOptimize;
};
/**

38
proto_encoder/BUILD.gn Executable file
View File

@ -0,0 +1,38 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# 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.
import("//build/ohos.gni")
import("//developtools/profiler/device/base/config.gni")
config("proto_encoder_config") {
include_dirs = [
"include",
"//third_party/bounds_checking_function/include",
"${OHOS_PROFILER_DIR}/interfaces/kits",
]
}
ohos_source_set("proto_encoder_source") {
output_name = "proto_encoder"
sources = [
"src/base_message.cpp",
"src/varint_encode.cpp",
]
public_configs = [
":proto_encoder_config",
"${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config",
]
public_deps = [ "//third_party/bounds_checking_function:libsec_static" ]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
part_name = "${OHOS_PROFILER_PART_NAME}"
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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.
*/
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
enum NUM {
ZERO = 0;
ONE = 1;
TWO = 2;
THREE = 3;
FOUR = 4;
}
message SubMessage {
int32 vint_int32 = 1;
int64 vint_int64 = 2;
uint32 vint_uint32 = 3;
uint64 vint_uint64 = 4;
}
message ExampleMessage {
// https://developers.google.com/protocol-buffers/docs/encoding
// ID Name Used For
// 0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum
int32 vint_int32 = 1;
int64 vint_int64 = 2;
uint32 vint_uint32 = 3;
uint64 vint_uint64 = 4;
sint32 vint_sint32 = 5;
sint64 vint_sint64 = 6;
bool vint_bool = 7;
NUM vint_enum = 8;
// 1 I64 fixed64, sfixed64, double
fixed64 I64_fixed64 = 11;
sfixed64 I64_sfixed64 = 12;
double I64_double = 13;
// 2 LEN string, bytes, embedded messages, packed repeated fields
string LEN_string = 21;
bytes LEN_bytes = 22; // maybe need identified by protoC
SubMessage LEN_sub = 23;
// repeated sint32 repeated_signed_vint = 24; // repeated signed(zigzag) not supported in libprotobuf
repeated int32 LEN_repeated_packed_signed_vint = 25; // [packed = true]
repeated uint32 LEN_repeated_packed_unsigned_vint = 26; // [packed = true]
repeated fixed64 LEN_repeated_packed_fixed = 27; // [packed = true]
repeated SubMessage repeated_LEN_sub = 28;
// 5 I32 fixed32, sfixed32, float
fixed32 I32_fixed32 = 51;
sfixed32 I32_sfixed32 = 52;
float I32_float = 53;
// 6 oneof
oneof oneoffield {
fixed64 oneof_fixed64 = 61;
string oneof_string = 62;
SubMessage oneof_sub = 63;
}
repeated ExampleMessage repeated_Example = 100;
}

View File

@ -0,0 +1,431 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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.
*/
#ifndef BASE_MESSAGE_H
#define BASE_MESSAGE_H
#include <functional>
#include <vector>
#include "securec.h"
#include "varint_encode.h"
// for struct RandomWriteCtx
#include "plugin_module_api.h"
namespace OHOS {
namespace Developtools {
namespace Profiler {
namespace ProtoEncoder {
// https://developers.google.com/protocol-buffers/docs/encoding
// ID Name Used For
// 0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum
// 1 I64 fixed64, sfixed64, double
// 2 LEN string, bytes, embedded messages, packed repeated fields
// 3 SGROUP group start (deprecated)
// 4 EGROUP group end (deprecated)
// 5 I32 fixed32, sfixed32, float
enum ProtoMessageType : uint32_t {
VARINT = 0,
I64 = 1,
LEN = 2,
I32 = 5,
};
constexpr uint8_t FIELDID_SHIFT = 3;
constexpr uint8_t SIZE_FIXED32 = 4;
constexpr uint8_t SIZE_FIXED64 = 8;
constexpr uint8_t SIZE_RESERVED_LEN = 4;
class MessagePool;
class BaseMessage {
public:
BaseMessage()
{
Reset(nullptr, nullptr);
}
explicit BaseMessage(RandomWriteCtx* writeCtx, MessagePool* subMessageStack = nullptr)
{
Reset(writeCtx, subMessageStack);
}
~BaseMessage()
{
if (isWriting_) {
Finish();
}
}
void Reset(RandomWriteCtx* writeCtx = nullptr, MessagePool* subMessageStack = nullptr)
{
if (subMessage_ != nullptr) {
FinishSubMessage();
}
writeCtx_ = writeCtx;
subMessageStack_ = subMessageStack;
backfillOffset_ = 0;
if (writeCtx == nullptr) {
// can not write
isWriting_ = false;
size_ = -1;
return;
}
size_ = 0;
isWriting_ = true;
}
// return current size of message has wrote, < 0 if writing failed
inline int32_t Size()
{
return size_;
}
// finish message and return size of message, < 0 if writing failed
inline int32_t Finish()
{
if (!isWriting_) {
return size_;
}
if (subMessage_ != nullptr) {
FinishSubMessage();
}
isWriting_ = false;
return size_;
}
// ID Name Used For
// 5 I32 fixed32, sfixed32, float
template<typename T>
void AddFixed32(uint32_t fieldId, T v)
{
static_assert(sizeof(T) == SIZE_FIXED32, "AddFixed32: T is not 32 bits");
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// max field size = varint(fieldId + type) + Fixed32(v)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_FIXED32,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::I32);
// T must be little-endian
if (memcpy_s(fieldMemory + tagSize, SIZE_FIXED32, &v, SIZE_FIXED32) != EOK) {
Drop();
return;
}
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + SIZE_FIXED32);
size_ += tagSize + SIZE_FIXED32;
}
// ID Name Used For
// 1 I64 fixed64, sfixed64, double
template<typename T>
void AddFixed64(uint32_t fieldId, T v)
{
static_assert(sizeof(T) == SIZE_FIXED64, "AddFixed64: T is not 64 bits");
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// max field size = varint(fieldId + type) + Fixed64(v)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_FIXED64,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::I64);
// T must be little-endian
if (memcpy_s(fieldMemory + tagSize, SIZE_FIXED64, &v, SIZE_FIXED64) != EOK) {
Drop();
return;
}
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + SIZE_FIXED64);
size_ += tagSize + SIZE_FIXED64;
}
// ID Name Used For(unsigned and 'intN' varint)
// 0 VARINT int32, int64, uint32, uint64, bool, enum
template<typename T>
void AddVarint(uint32_t fieldId, T v)
{
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// max field size = varint(fieldId + type) + varint(v)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + VARINT_ENCODE_MAX_SIZE,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::VARINT);
fieldSize += EncodeVarint(fieldMemory + fieldSize, v);
writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
size_ += fieldSize;
}
// ID Name Used For('sintN' varint, ZigZag encode)
// 0 VARINT sint32, sint64
template<typename T>
void AddZigZagVarint(uint32_t fieldId, T v)
{
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// max field size = varint(fieldId + type) + varint(v)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + VARINT_ENCODE_MAX_SIZE,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::VARINT);
fieldSize += EncodeZigZagVarint(fieldMemory + fieldSize, v);
writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
size_ += fieldSize;
}
// ID Name Used For
// 2 LEN bytes, string
void AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize);
// add customize data, return RandomWriteCtx pointer, caller implement:
// RandomWriteCtx* writeCtx = StartAddBytes();
// 1, write data by writeCtx->write() directly;
// 2, constructor Message object by writeCtx, and fill data by method of Message
// FinishAddBytes(size);
RandomWriteCtx* StartAddBytes(uint32_t fieldId);
void FinishAddBytes(int32_t size);
// get data by getData(), implement in getData() function:
// 1, write data by randomWriteCtx->write() directly;
// 2, constructor Message object by randomWriteCtx, and fill data by method of Message
using GetDataCallback = std::function<int32_t(RandomWriteCtx* randomWriteCtx)>;
void AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData);
// ID Name Used For
// 2 LEN embedded messages
template<typename T>
T* AddSubMessage(uint32_t fieldId)
{
static_assert(std::is_base_of<BaseMessage, T>::value,
"SubMessage must be a derived class of BaseMessage");
static_assert(sizeof(T) == sizeof(BaseMessage),
"Size of SubMessage class must be equal to BaseMessage");
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
// return message self pointer for business,
// business can call message->set_XXX() without checking message is nullptr
return static_cast<T*>(this);
}
uint8_t* fieldMemory = nullptr;
// varint(fieldId) + varint(len)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
&fieldMemory, &backfillOffset_)) {
Drop();
return static_cast<T*>(this);
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
backfillOffset_ += tagSize;
size_ += tagSize;
// reserve length space
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN);
if (!AllocateSubMessage()) {
Drop();
return static_cast<T*>(this);
}
return static_cast<T*>(subMessage_);
}
// ID Name Used For
// 2 LEN packed repeated fields(unsigned and 'intN' varint)
template<typename T>
inline void AddPackedVarint(uint32_t fieldId, const T* array, uint32_t arrayCount)
{
if (arrayCount == 0) {
return;
}
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint32_t maxLen = 0;
uint32_t lenSize = GetPackedVarintLenSize(arrayCount, sizeof(T), maxLen);
if (lenSize == 0) {
Drop();
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// varint(fieldId) + lenSize + maxLen
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + lenSize + maxLen,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
// encode array of varint first
uint32_t dataSize = 0;
uint8_t* pData = fieldMemory + tagSize + lenSize;
for (uint32_t i = 0; i < arrayCount; i++) {
dataSize += EncodeVarint(pData + dataSize, *array);
array++;
}
// varint(Length)
EncodeVarintPadding(fieldMemory + tagSize, dataSize, lenSize);
size_ += tagSize + lenSize + dataSize;
// seek to tail
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + lenSize + dataSize);
}
// ID Name Used For
// 2 LEN packed repeated fields(I32 and I64)
template<typename T>
inline void AddPackedFixed(uint32_t fieldId, const T* array, uint32_t arrayCount)
{
static_assert(sizeof(T) == SIZE_FIXED32 || sizeof(T) == SIZE_FIXED64,
"AddPackedFixed: T is not 32 or 64 bits");
if (arrayCount == 0) {
return;
}
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint32_t dataSize = arrayCount * sizeof(T);
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// varint(fieldId) + varint(dataSize) + dataSize
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
tagSize += EncodeVarint(fieldMemory + tagSize, dataSize);
if (memcpy_s(fieldMemory + tagSize, dataSize, array, dataSize) != EOK) {
Drop();
return;
}
size_ += tagSize + dataSize;
// seek to tail
writeCtx_->seek(writeCtx_, fieldOffset + tagSize + dataSize);
}
private:
RandomWriteCtx* writeCtx_ = nullptr;
MessagePool* subMessageStack_ = nullptr;
BaseMessage* subMessage_ = nullptr;
int32_t size_ = 0;
uint32_t backfillOffset_ = 0;
bool isWriting_ = true; // false when Finish() or Drop()
bool AllocateSubMessage();
void FinishSubMessage();
inline void Drop()
{
isWriting_ = false;
size_ = -1;
return;
}
};
constexpr uint32_t DEFAULT_SUBMESSAGE_DEPTH = 10;
// MessagePool is cache of the BaseMessage's submessage, avoid new and delete multiple times
// ONE BaseMessage corresponds to ONE MessagePool
class MessagePool {
public:
explicit MessagePool(uint32_t depth = DEFAULT_SUBMESSAGE_DEPTH)
{
Reset(depth);
}
inline void Reset(uint32_t depth = DEFAULT_SUBMESSAGE_DEPTH)
{
messageCache_.resize(depth);
cursor_ = 0;
}
BaseMessage* Get()
{
if (cursor_ < messageCache_.size()) {
return &messageCache_[cursor_++];
} else {
auto& msg = messageCache_.emplace_back();
cursor_++;
return &msg;
}
}
inline void Release()
{
if (cursor_ > 0) {
cursor_--;
}
}
private:
std::vector<BaseMessage> messageCache_;
uint32_t cursor_ = 0;
};
} // namespace ProtoEncoder
} // namespace Profiler
} // namespace Developtools
} // namespace OHOS
#endif // BASE_MESSAGE_H

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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.
*/
#ifndef VARINT_ENCODE_H
#define VARINT_ENCODE_H
#include <cinttypes>
#include <cstddef>
#include <type_traits>
#include <cstdint>
namespace OHOS {
namespace Developtools {
namespace Profiler {
namespace ProtoEncoder {
constexpr uint32_t VARINT32_SIZE = 4;
constexpr uint32_t VARINT32_ENCODE_SIZE = 5;
constexpr uint32_t VARINT64_SIZE = 8;
constexpr uint32_t VARINT64_ENCODE_SIZE = 10;
constexpr uint32_t VARINT_ENCODE_MAX_SIZE = VARINT64_ENCODE_SIZE;
constexpr uint32_t VARINT_MAX_1BYTE = (1u << (7 * 1)) - 1;
constexpr uint32_t VARINT_MAX_2BYTE = (1u << (7 * 2)) - 1;
constexpr uint32_t VARINT_MAX_3BYTE = (1u << (7 * 3)) - 1;
constexpr uint32_t VARINT_MAX_4BYTE = (1u << (7 * 4)) - 1;
constexpr uint8_t VARINT_PAYLOAD_BITS = 7;
constexpr uint8_t VARINT_MASK_PAYLOAD = 0x7F;
constexpr uint8_t VARINT_MASK_MSB = 0x80;
inline uint32_t GetPackedVarintLenSize(uint32_t itemCount, uint32_t itemSize, uint32_t& len)
{
len = itemCount;
if (itemSize == VARINT32_SIZE) {
len = itemCount * VARINT32_ENCODE_SIZE;
} else if (itemSize == VARINT64_SIZE) {
len = itemCount * VARINT64_ENCODE_SIZE;
} // else bool is 1 byte
const uint32_t one = 1;
const uint32_t two = 2;
const uint32_t three = 3;
const uint32_t four = 4;
if (len <= VARINT_MAX_1BYTE) {
return one;
} else if (len <= VARINT_MAX_2BYTE) {
return two;
} else if (len <= VARINT_MAX_3BYTE) {
return three;
} else if (len <= VARINT_MAX_4BYTE) {
return four;
}
return 0; // illegal, too large
}
template<typename T>
inline typename std::make_unsigned<T>::type EncodeZigZag(T v)
{
if (v >= 0) {
return ((typename std::make_unsigned<T>::type)(v) << 1);
}
return ((typename std::make_unsigned<T>::type)(~v) << 1) + 1;
}
template<typename T>
inline uint32_t EncodeVarint(uint8_t* buf, T v)
{
// https://developers.google.com/protocol-buffers/docs/encoding
// Unsigned Integers and Signed Integers(intN)
uint64_t value = (uint64_t)v;
uint32_t size = 0;
while (value > (uint64_t)VARINT_MAX_1BYTE) {
buf[size] = (VARINT_MASK_PAYLOAD & value) | VARINT_MASK_MSB;
size++;
value >>= VARINT_PAYLOAD_BITS;
}
buf[size] = (VARINT_MASK_PAYLOAD & value);
size++;
return size;
}
template<typename T>
inline uint32_t EncodeZigZagVarint(uint8_t* buf, T v)
{
return EncodeVarint(buf, EncodeZigZag(v));
}
template<typename T>
inline void EncodeVarintPadding(uint8_t* buf, T v, uint32_t paddingSize)
{
uint32_t size = 0;
paddingSize--;
while (size < paddingSize) {
buf[size] = (VARINT_MASK_PAYLOAD & v) | VARINT_MASK_MSB;
size++;
v >>= VARINT_PAYLOAD_BITS;
}
buf[size] = (VARINT_MASK_PAYLOAD & v);
}
} // namespace ProtoEncoder
} // namespace Profiler
} // namespace Developtools
} // namespace OHOS
#endif // VARINT_ENCODE_H

View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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 "base_message.h"
#include "securec.h"
#include "varint_encode.h"
namespace OHOS {
namespace Developtools {
namespace Profiler {
namespace ProtoEncoder {
bool BaseMessage::AllocateSubMessage()
{
if (subMessageStack_ == nullptr) {
subMessage_ = new (std::nothrow) BaseMessage(writeCtx_);
} else {
subMessage_ = subMessageStack_->Get();
}
if (subMessage_ == nullptr) {
return false;
}
subMessage_->Reset(writeCtx_, subMessageStack_);
return true;
}
void BaseMessage::FinishSubMessage()
{
int32_t subSize = subMessage_->Finish();
if (subMessageStack_ == nullptr) {
delete subMessage_;
} else {
subMessageStack_->Release();
}
subMessage_ = nullptr;
if (subSize < 0) {
Drop();
return;
}
uint8_t* fieldMemory = nullptr;
// backfill length
writeCtx_->seek(writeCtx_, backfillOffset_);
if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN,
&fieldMemory, &backfillOffset_)) {
Drop();
return;
}
if (subSize == 0) {
// reduce the size
*fieldMemory = 0;
writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
size_++;
return;
}
// varint(Length)
EncodeVarintPadding(fieldMemory, subSize, SIZE_RESERVED_LEN);
size_ += SIZE_RESERVED_LEN + subSize;
// seek to tail
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + subSize);
}
void BaseMessage::AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize)
{
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// max field size = varint(fieldId + type) + varint(dataSize) + dataSize
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
fieldSize += EncodeVarint(fieldMemory + fieldSize, dataSize);
if (dataSize != 0) {
if (memcpy_s(fieldMemory + fieldSize, dataSize, data, dataSize) != EOK) {
Drop();
return;
}
}
fieldSize += dataSize;
size_ += fieldSize;
// seek to tail
writeCtx_->seek(writeCtx_, fieldOffset + fieldSize);
}
RandomWriteCtx* BaseMessage::StartAddBytes(uint32_t fieldId)
{
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
// finished or dropped
return nullptr;
}
uint8_t* fieldMemory = nullptr;
// max field size = varint(fieldId + type) + varint(len)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
&fieldMemory, &backfillOffset_)) {
Drop();
return nullptr;
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
backfillOffset_ += tagSize;
size_ += tagSize;
// reserve length space
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN);
return writeCtx_;
}
void BaseMessage::FinishAddBytes(int32_t size)
{
if (size < 0) {
Drop();
return;
}
uint8_t* fieldMemory = nullptr;
// backfill length
writeCtx_->seek(writeCtx_, backfillOffset_);
if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &backfillOffset_)) {
Drop();
return;
}
if (size == 0) {
// reduce the size
*fieldMemory = 0;
writeCtx_->seek(writeCtx_, backfillOffset_ + 1);
size_++;
return;
}
// varint(Length)
EncodeVarintPadding(fieldMemory, size, SIZE_RESERVED_LEN);
size_ += SIZE_RESERVED_LEN + size;
// seek to tail
writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + size);
}
void BaseMessage::AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData)
{
if (!getData) {
return;
}
if (subMessage_ != nullptr) {
FinishSubMessage();
}
if (!isWriting_) {
return;
}
uint8_t* fieldMemory = nullptr;
uint32_t fieldOffset = 0;
// max field size = varint(fieldId + type) + varint(len)
if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN,
&fieldMemory, &fieldOffset)) {
Drop();
return;
}
uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN);
fieldOffset += tagSize;
size_ += tagSize;
// reserve length space
writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN);
int32_t dataSize = getData(writeCtx_);
if (dataSize < 0) {
Drop();
return;
}
// backfill length
writeCtx_->seek(writeCtx_, fieldOffset);
if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &fieldOffset)) {
Drop();
return;
}
if (dataSize == 0) {
// reduce the size
*fieldMemory = 0;
writeCtx_->seek(writeCtx_, fieldOffset + 1);
size_++;
return;
}
EncodeVarintPadding(fieldMemory, dataSize, SIZE_RESERVED_LEN);
size_ += SIZE_RESERVED_LEN + dataSize;
// seek to tail
writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN + dataSize);
}
} // namespace ProtoEncoder
} // namespace Profiler
} // namespace Developtools
} // namespace OHOS

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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 "varint_encode.h"
namespace OHOS {
namespace Developtools {
namespace Profiler {
namespace ProtoEncoder {
} // namespace ProtoEncoder
} // namespace Profiler
} // namespace Developtools
} // namespace OHOS

101
proto_encoder/test/BUILD.gn Executable file
View File

@ -0,0 +1,101 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# 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.
import("//build/test.gni")
import("//developtools/profiler/device/base/config.gni")
import("//developtools/profiler/protos/protos.gni")
module_output_path = "${OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH}/proto_encoder"
config("module_private_config") {
visibility = [ ":*" ]
}
protos_dir = "../example/"
protos_root_dir = rebase_path(protos_dir, root_build_dir)
proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(protos_dir, "//")
proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir)
protos_defines = [ "$protos_dir" + "example.proto" ]
example_codegen_all = []
foreach(proto, protos_defines) {
name = get_path_info(proto, "name")
example_codegen_all += [
"$proto_out_dir/$name.pb.h",
"$proto_out_dir/$name.pb.cc",
"$proto_out_dir/$name.pbencoder.h",
"$proto_out_dir/$name.pbencoder.cc",
]
}
action("proto_gen_source") {
script = "${OHOS_PROFILER_DIR}/build/protoc.sh"
sources = protos_defines
outputs = example_codegen_all
args = [
"$libc_dir_proto",
"$root_output_dir_proto",
"$proto_rel_out_dir",
"--cpp_out",
"$proto_rel_out_dir",
"--proto_path",
"$protos_root_dir",
]
args += rebase_path(sources, root_build_dir)
deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})",
"${OHOS_PROFILER_DIR}/device/services/ipc:protoencoder_plugin(${host_toolchain})",
]
}
ohos_source_set("proto_example_source") {
deps = [
":proto_gen_source",
]
include_dirs = [ "$proto_out_dir" ]
sources = example_codegen_all
public_deps = [
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf",
"${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite",
]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
part_name = "${OHOS_PROFILER_PART_NAME}"
}
ohos_unittest("proto_encoder_ut") {
module_out_path = module_output_path
sources = [
"unittest/base_message_unittest.cpp",
"unittest/varint_encode_unittest.cpp",
]
deps = [
":proto_example_source",
"../:proto_encoder_source",
"//third_party/googletest:gtest_main",
]
include_dirs = [
"../include",
"../example",
"//third_party/googletest/googletest/include/gtest",
"$proto_out_dir",
]
configs = [ ":module_private_config" ]
subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}"
part_name = "${OHOS_PROFILER_PART_NAME}"
}
group("unittest") {
testonly = true
deps = [ ":proto_encoder_ut" ]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,319 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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 <cstdlib>
#include <limits>
#include <vector>
#include <gtest/gtest.h>
#include "varint_encode.h"
namespace OHOS {
namespace Developtools {
namespace Profiler {
using namespace testing::ext;
using namespace ProtoEncoder;
class VarintEncodeUnittest : public ::testing::Test {
public:
static void SetUpTestCase() {};
static void TearDownTestCase() {};
void SetUp() {};
void TearDown() {};
const uint32_t two = 2;
const uint32_t three = 3;
const uint32_t four = 4;
};
HWTEST_F(VarintEncodeUnittest, GetPackedVarintLenSize, TestSize.Level1)
{
uint32_t len = 0;
uint32_t itemCount = 0;
uint32_t itemSize = sizeof(char);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
EXPECT_EQ(len, (uint32_t)0);
itemSize = sizeof(int32_t);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
EXPECT_EQ(len, itemCount * itemSize);
itemSize = sizeof(int64_t);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
EXPECT_EQ(len, itemCount * itemSize);
itemSize = sizeof(char);
itemCount = VARINT_MAX_1BYTE;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
EXPECT_EQ(len, itemCount * itemSize);
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
EXPECT_EQ(len, itemCount * itemSize);
itemCount = VARINT_MAX_2BYTE;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
EXPECT_EQ(len, itemCount * itemSize);
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
EXPECT_EQ(len, itemCount * itemSize);
itemCount = VARINT_MAX_3BYTE;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
EXPECT_EQ(len, itemCount * itemSize);
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
EXPECT_EQ(len, itemCount * itemSize);
itemCount = VARINT_MAX_4BYTE;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
EXPECT_EQ(len, itemCount * itemSize);
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0);
EXPECT_EQ(len, itemCount * itemSize);
itemSize = sizeof(int32_t);
itemCount = VARINT_MAX_1BYTE / (itemSize + 1);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount = VARINT_MAX_2BYTE / (itemSize + 1);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount = VARINT_MAX_3BYTE / (itemSize + 1);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount = VARINT_MAX_4BYTE / (itemSize + 1);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0);
EXPECT_EQ(len, itemCount * (itemSize + 1));
itemSize = sizeof(int64_t);
itemCount = VARINT_MAX_1BYTE / (itemSize + two);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount = VARINT_MAX_2BYTE / (itemSize + two);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount = VARINT_MAX_3BYTE / (itemSize + two);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount = VARINT_MAX_4BYTE / (itemSize + two);
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four);
EXPECT_EQ(len, itemCount * (itemSize + two));
itemCount++;
EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0);
EXPECT_EQ(len, itemCount * (itemSize + two));
}
HWTEST_F(VarintEncodeUnittest, EncodeZigZag, TestSize.Level1)
{
int8_t signed8 = 0;
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)0);
signed8 = -1;
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)1);
signed8 = 1;
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(signed8 * two));
std::srand(std::time(nullptr));
int rand = std::rand();
signed8 = static_cast<int8_t>rand;
if (signed8 >= 0) {
// n are encoded as 2 * n
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(signed8 * two));
} else {
// -n are encoded as 2 * n + 1
EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(-signed8 - 1 + -signed8));
}
signed8 = std::numeric_limits<int8_t>::min();
EXPECT_EQ(EncodeZigZag(signed8), std::numeric_limits<uint8_t>::max());
signed8 = std::numeric_limits<int8_t>::max();
EXPECT_EQ(EncodeZigZag(signed8), std::numeric_limits<uint8_t>::max() - 1);
int32_t signed32 = 0;
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)0);
signed32 = -1;
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)1);
signed32 = 1;
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(signed32 * two));
std::srand(rand);
rand = std::rand();
signed32 = static_cast<int32_t>rand;
if (signed32 >= 0) {
// n are encoded as 2 * n
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(signed32 * two));
} else {
// -n are encoded as 2 * n + 1
EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(-signed32 - 1 + -signed32));
}
signed32 = std::numeric_limits<int32_t>::min();
EXPECT_EQ(EncodeZigZag(signed32), std::numeric_limits<uint32_t>::max());
signed32 = std::numeric_limits<int32_t>::max();
EXPECT_EQ(EncodeZigZag(signed32), std::numeric_limits<uint32_t>::max() - 1);
int64_t signed64 = 0;
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)0);
signed64 = -1;
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)1);
signed64 = 1;
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(signed64 * two));
std::srand(rand);
rand = std::rand();
signed64 = static_cast<int64_t>rand;
if (signed64 >= 0) {
// n are encoded as 2 * n
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(signed64 * two));
} else {
// -n are encoded as 2 * n + 1
EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(-signed64 - 1 + -signed64));
}
signed64 = std::numeric_limits<int64_t>::min();
EXPECT_EQ(EncodeZigZag(signed64), std::numeric_limits<uint64_t>::max());
signed64 = std::numeric_limits<int64_t>::max();
EXPECT_EQ(EncodeZigZag(signed64), std::numeric_limits<uint64_t>::max() - 1);
}
bool CompareBytes(const uint8_t* a, const uint8_t* b, size_t size)
{
for (size_t i = 0; i < size; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
const uint8_t ENCODE_BYTES_MIN_BOOL[] = {0x00};
const uint8_t ENCODE_BYTES_MAX_BOOL[] = {0x01};
const uint8_t ENCODE_BYTES_MIN_S8[] = {0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01};
const uint8_t ENCODE_BYTES_MAX_S8[] = {0x7F};
const uint8_t ENCODE_BYTES_MIN_U8[] = {0x00};
const uint8_t ENCODE_BYTES_MAX_U8[] = {0xFF, 0x01};
const uint8_t ENCODE_BYTES_MIN_S32[] = {0x80, 0x80, 0x80, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x01};
const uint8_t ENCODE_BYTES_MAX_S32[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x07};
const uint8_t ENCODE_BYTES_MIN_U32[] = {0x00};
const uint8_t ENCODE_BYTES_MAX_U32[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x0F};
const uint8_t ENCODE_BYTES_MIN_S64[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01};
const uint8_t ENCODE_BYTES_MAX_S64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
const uint8_t ENCODE_BYTES_MIN_U64[] = {0x00};
const uint8_t ENCODE_BYTES_MAX_U64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01};
HWTEST_F(VarintEncodeUnittest, EncodeVarint, TestSize.Level1)
{
uint8_t buf[VARINT_ENCODE_MAX_SIZE] = {0};
bool b = std::numeric_limits<bool>::min();
EXPECT_EQ(EncodeVarint(buf, b), (uint32_t)sizeof(ENCODE_BYTES_MIN_BOOL));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_BOOL, sizeof(ENCODE_BYTES_MIN_BOOL)));
b = std::numeric_limits<bool>::max();
EXPECT_EQ(EncodeVarint(buf, b), (uint32_t)sizeof(ENCODE_BYTES_MAX_BOOL));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_BOOL, sizeof(ENCODE_BYTES_MAX_BOOL)));
int8_t s8 = std::numeric_limits<int8_t>::min();
EXPECT_EQ(EncodeVarint(buf, s8), (uint32_t)sizeof(ENCODE_BYTES_MIN_S8));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S8, sizeof(ENCODE_BYTES_MIN_S8)));
s8 = std::numeric_limits<int8_t>::max();
EXPECT_EQ(EncodeVarint(buf, s8), (uint32_t)sizeof(ENCODE_BYTES_MAX_S8));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S8, sizeof(ENCODE_BYTES_MAX_S8)));
uint8_t u8 = std::numeric_limits<uint8_t>::min();
EXPECT_EQ(EncodeVarint(buf, u8), (uint32_t)sizeof(ENCODE_BYTES_MIN_U8));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U8, sizeof(ENCODE_BYTES_MIN_U8)));
u8 = std::numeric_limits<uint8_t>::max();
EXPECT_EQ(EncodeVarint(buf, u8), (uint32_t)sizeof(ENCODE_BYTES_MAX_U8));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U8, sizeof(ENCODE_BYTES_MAX_U8)));
int32_t s32 = std::numeric_limits<int32_t>::min();
EXPECT_EQ(EncodeVarint(buf, s32), (uint32_t)sizeof(ENCODE_BYTES_MIN_S32));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S32, sizeof(ENCODE_BYTES_MIN_S32)));
s32 = std::numeric_limits<int32_t>::max();
EXPECT_EQ(EncodeVarint(buf, s32), (uint32_t)sizeof(ENCODE_BYTES_MAX_S32));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S32, sizeof(ENCODE_BYTES_MAX_S32)));
uint32_t u32 = std::numeric_limits<uint32_t>::min();
EXPECT_EQ(EncodeVarint(buf, u32), (uint32_t)sizeof(ENCODE_BYTES_MIN_U32));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U32, sizeof(ENCODE_BYTES_MIN_U32)));
u32 = std::numeric_limits<uint32_t>::max();
EXPECT_EQ(EncodeVarint(buf, u32), (uint32_t)sizeof(ENCODE_BYTES_MAX_U32));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U32, sizeof(ENCODE_BYTES_MAX_U32)));
int64_t s64 = std::numeric_limits<int64_t>::min();
EXPECT_EQ(EncodeVarint(buf, s64), (uint32_t)sizeof(ENCODE_BYTES_MIN_S64));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S64, sizeof(ENCODE_BYTES_MIN_S64)));
s64 = std::numeric_limits<int64_t>::max();
EXPECT_EQ(EncodeVarint(buf, s64), (uint32_t)sizeof(ENCODE_BYTES_MAX_S64));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S64, sizeof(ENCODE_BYTES_MAX_S64)));
uint64_t u64 = std::numeric_limits<uint64_t>::min();
EXPECT_EQ(EncodeVarint(buf, u64), (uint32_t)sizeof(ENCODE_BYTES_MIN_U64));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U64, sizeof(ENCODE_BYTES_MIN_U64)));
u64 = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(EncodeVarint(buf, u64), (uint32_t)sizeof(ENCODE_BYTES_MAX_U64));
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U64, sizeof(ENCODE_BYTES_MAX_U64)));
}
HWTEST_F(VarintEncodeUnittest, EncodeVarintPadding, TestSize.Level1)
{
const uint8_t paddingByte = 0x80;
uint8_t buf[VARINT_ENCODE_MAX_SIZE] = {0};
uint64_t u64 = 1;
EncodeVarintPadding(buf, u64, VARINT_ENCODE_MAX_SIZE);
uint32_t i = 1;
while (i < VARINT_ENCODE_MAX_SIZE - 1) {
EXPECT_EQ(buf[i++], paddingByte);
}
EXPECT_EQ(buf[i], (uint8_t)0);
u64 = std::numeric_limits<uint64_t>::max();
EncodeVarintPadding(buf, u64, VARINT_ENCODE_MAX_SIZE);
EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U64, sizeof(ENCODE_BYTES_MAX_U64)));
}
} // namespace Profiler
} // namespace Developtools
} // namespace OHOS