简体   繁体   English

nanopb - 如何优化编码以提高运行时速度

[英]nanopb - how to optimize encoding for runtime speed

I am using nanopb to do logging on an embedded system: my logging messages will be .proto messages.我正在使用nanopb在嵌入式系统上进行日志记录:我的日志记录消息将是.proto消息。
Speed of encoding is the most important factor;编码速度是最重要的因素; I have plenty of RAM and flash.我有足够的内存和 flash。

QUESTION问题
Specific to nanopb , how do I minimize encoding time?具体到nanopb ,如何最大限度地减少编码时间?

I know of all the C optimizations I could make: inline functions, set pb_encode functions in RAM instead of flash, etc我知道我可以进行的所有 C 优化:内联函数,在 RAM 中设置pb_encode函数而不是 flash 等

Would it make a difference if I use all fixed-size types in my .proto file?如果我在.proto文件中使用所有固定大小的类型会有所不同吗?

The easy methods I'm aware of are:我知道的简单方法是:

  • Encode to memory buffer and enable PB_BUFFER_ONLY at compile time.编码为 memory 缓冲区并在编译时启用PB_BUFFER_ONLY
  • If platform is little-endian and size of byte is 8 bits, you can define PB_LITTLE_ENDIAN_8BIT .如果平台是 little-endian 且字节大小是 8 位,则可以定义PB_LITTLE_ENDIAN_8BIT It should be detected automatically on most compilers, though.不过,它应该在大多数编译器上自动检测到。
  • In your message definition, minimize the amount of submessages.在您的消息定义中,尽量减少子消息的数量。 They require separate size calculations which take time.它们需要单独的尺寸计算,这需要时间。

These could result in speed improvements up to 2x.这些可能会导致速度提高多达 2 倍。


It is further possible to speed up encoding by programming direct calls to the encoding functions, instead of going through the message structure and descriptor loops.通过编程对编码函数的直接调用,而不是通过消息结构和描述符循环,还可以进一步加快编码速度。 I expect this to increase encoding speed up to 5x.我希望这可以将编码速度提高到 5 倍。 Some knowledge of protobuf encoding spec will be needed.需要一些关于protobuf 编码规范的知识。

For example, for this message:例如,对于此消息:

message LogMessage {
    uint64 timestamp = 1;
    float batterylevel = 2;
    string logmessage = 3;
}

you could do:你可以这样做:

void writelog(const char *logmsg)
{
    uint8_t buffer[256];
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

    // Get system state
    uint64_t timestamp = get_system_timestamp();
    float batterylevel = get_batterylevel();

    // Encode timestamp
    pb_encode_tag(&stream, PB_WT_VARINT, LogMessage_timestamp_tag);
    pb_encode_varint(&stream, timestamp);

    // Encode battery level
    pb_encode_tag(&stream, PB_WT_32BIT, LogMessage_batterylevel_tag);
    pb_encode_fixed32(&stream, &batterylevel);

    // If we have explicit message, encode it also.
    if (logmsg)
    {
       pb_encode_tag(&stream, PB_WT_STRING, LogMessage_logmessage_tag);
       pb_encode_string(&stream, logmsg, strlen(logmsg));
    }

    // Save the encoded message data to storage
    save_log(buffer, stream.bytes_written);
}

While this results in hard-coding part of the message definition, the backward- and forward compatibility of protobuf messages works as usual.虽然这会导致消息定义的部分硬编码,但 protobuf 消息的向后和向前兼容性照常工作。 The tag numbers can be accessed by the Message_field_tag macros that are generated by nanopb generator.标记号可以通过 nanopb 生成器生成的Message_field_tag宏访问。 The field types are defined in the C code, but they are also embedded in the encoded messages so any mismatches will be detected on the decoding side.字段类型在 C 代码中定义,但它们也嵌入在编码消息中,因此将在解码端检测到任何不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM