Skip to content

C flatcc builder (put) optimization #8

Open

Description

@vaind

The generated code currently calls flatcc_builder_finalize_aligned_buffer() which returns a copy of the builder buffer. The returned buffer must be freed by calling flatcc_builder_aligned_free(), in addition to freeing the builder using flatcc_builder_clear(). Have a look at the following sample from README.md

obx_id task_put(OBX_box* box, Task* task) {
    flatcc_builder_t builder;
    flatcc_builder_init(&builder);

    size_t size = 0;
    void* buffer = NULL;

    // Note: Task_to_flatbuffer() is provided by the generated code
    obx_id id = 0;
    if (Task_to_flatbuffer(&builder, task, &buffer, &size)) {
        id = obx_box_put_object(box, buffer, size, OBXPutMode_PUT);  // returns 0 on error
    }

    flatcc_builder_clear(&builder);
    if (buffer) flatcc_builder_aligned_free(buffer);

    if (id == 0) {
        // TODO: won't be able to print the right error if it occurred in Task_to_flatbuffer(), 
        //  i.e. outside objectbox
        print_last_error();
    } else {
        task->id = id;  // Note: we're updating the ID on new objects for convenience
    }

    return id;
}

We should have a look if/how we can optimize this, in terms of performance (avoiding the memory copy if possible) and usability.

Activity

  1. vaind commented on Jun 23, 2020

    @vaind
    ContributorAuthor

    Note: I'm not sure the copy could be avoided, considering how flatcc_builder works - it doesn't produce the final output on the first call, only when calling "finalize". Maybe there's another mode similar to other flatbuffers implementations producing the final buffer right away without the in-between "emitter"?

    Maybe @mikkelfj has some suggestions?

  2. mikkelfj commented on Jun 23, 2020

    @mikkelfj

    The copy can be avoided, to a degree:

    You can call a different version of finalize that accepts a fixed size buffer, and you can call yet another function to detect the size of the buffer required.

    However, the default backend emitter of the builder is collecting data in chained pages, not in contiguous memory, so this memory must be copied out in order to read the data as a buffer. And this data generally needs to be aligned to the largest alignment unit used in the buffer. Usually 8 bytes suffice, but char mybuf[4096]; will not be aligned. While this works on most CPU's today, the verifier will still complain due to semantics.

    If you want to further optimize, you can provide you own emitter backend. It is essentially a simple callback that receives an iovec array of small chunks of data to copy. There are a few emitter examples in the test directory.

  3. greenrobot commented on Jun 23, 2020

    @greenrobot
    Member

    Another topic: are we able to reuse flatcc_builder_t? I don't recall if we can cache it.

    PS.: flatcc related optimizations can be done after 1.0

  4. mikkelfj commented on Jun 23, 2020

    @mikkelfj

    I can't answer that, but the mentioned list of chained pages will be recycled efficiently if you do cache the builder, and so will several internal stacks. You can control how much memory the builder retains between builds in case you have a large spike. See custom version of the reset call.

  5. vaind commented on Jul 15, 2020

    @vaind
    ContributorAuthor

    Also see the discussion about an overload for generated _put() and _get() functions #11 (review)

  6. vaind commented on Feb 15, 2021

    @vaind
    ContributorAuthor

    Also to keep in mind: there's an internal discussion/feature request for providing flatbuffers serialization as part of the C-API. It's mainly for other language bindings but it would also solve this issue (data copy), simplify the code generator (we could have the same code for C++ and C) and drop the C flatc dependency for end-users altogether. Internal issue number: 363

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions