Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify the memory allocation method of matd_t to comply with ISO standards #362

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

zhaoxi-scut
Copy link

The original way of writing matd_t was

typedef struct
{
    unsigned int nrows, ncols;
    double data[];
//    double *data;
} matd_t;

which does not conform to the ISO standard. For example, it will generate a warning in C++ compilers such as g++, with the following message:

/path/to/apriltag/common/matd.h:48:12: warning: ISO C++ forbids flexible array member ‘data’ [-Wpedantic]
   48 |     double data[];
      |            ^~~~

Therefore, it was changed to use double *, and separate memory was allocated for m and m->data. Additionally, resource release for m->data was added in the matd_destroy function.

Copy link
Collaborator

@christian-rauch christian-rauch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add the compiler flags (add_compile_options(-Wall -Wextra -Wpedantic -Werror)) to make sure that the warning does not appear again?

common/matd.c Outdated
m->nrows = rows;
m->ncols = cols;
m->data = calloc(rows * cols, sizeof(TYPE));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has the potential to leek memory, if TYPE gets redefined. We should either stick with double wherever matd_t is used, or replace all usages of double with matd_t by TYPE macro.

@zhaoxi-scut
Copy link
Author

The original line 46 in CMakeLists.txt (-Wpedantic) was commented out, now it is uncommented. 😃

@christian-rauch
Copy link
Collaborator

The original line 46 in CMakeLists.txt (-Wpedantic) was commented out, now it is uncommented. 😃

Right. It was actually me who left this commented out (9959575). Probably a reminder that about unsolved issues.

But now the checking seems to be too strict as the CI fails for clang with gnu-zero-variadic-macro-arguments (https://github.com/AprilRobotics/apriltag/actions/runs/11869401035/job/33080645704?pr=362). If you don't know how to fix this, you can add a -Wno-gnu-zero-variadic-macro-arguments to skip that specific issue.

@mkrogius
Copy link
Contributor

The original approach in matd_t was done intentionally with the goal of improving performance. It saves one pointer dereference by keeping data within the matd_t struct instead of having it allocated separately.

I doubt this performance difference matters for the usage of matd within this project. Since most of the compute of apiltag detection is not within matrix calculations I imagine it won't make much difference. But it might be nice to just double check for a single image that this doesn't make a noticeable difference to compute speed

@zhaoxi-scut
Copy link
Author

zhaoxi-scut commented Nov 17, 2024

Alright, to pass the CI-CD, I temporarily commented out the -Wpedantic.

The performance improvement brought by using double data[] might not be significant and instead introduces some safety issues. I did a benchmark test on the performance. 😃

----------------------------------------------------------------------------------
Benchmark                                        Time             CPU   Iterations
----------------------------------------------------------------------------------
Ptr (double *data)/iterations:10000000        30.9 ns         30.9 ns     10000000
FAM (double data[])/iterations:10000000       18.1 ns         18.1 ns     10000000

As you can see, the performance improvement brought by using flexible array memory is indeed noticeable, but it is at the ns level, mainly occurring in the calloc calls, and the performance improvement in image detection is almost negligible. Therefore, I also conducted an overall performance test:

static void matd(benchmark::State &state)
{
    cv::Mat gray = cv::imread("1.png", cv::IMREAD_GRAYSCALE);
    auto tf = tag25h9_create();
    auto td = apriltag_detector_create();
    // init
    apriltag_detector_add_family(td, tf);


    for (auto _ : state)
    {
        // format conversion
        image_u8_t apriltag_img = {gray.cols, gray.rows, gray.cols, gray.data};
        // detect
        zarray_t *detections = apriltag_detector_detect(td, &apriltag_img);
        // release
        apriltag_detections_destroy(detections);
    }

    apriltag_detector_destroy(td);
    tag25h9_destroy(tf);
}

BENCHMARK(matd)->Name("detect by (double *data)")->Iterations(100);

And the result of this perf test are as follows:

-----------------------------------------------------------------------------------
Benchmark                                         Time             CPU   Iterations
-----------------------------------------------------------------------------------
detect by (double *data)/iterations:100     1862518 ns      1862318 ns          100
detect by (double data[])/iterations:100    1867628 ns      1867464 ns          100

In fact, I use this project as a 3rdparty library for my own project. During the build, a flexible array memory double data[] warning appeared because I included the apriltag.h header file in a .cpp file, and this header file also nested includes matd.h, where the flexible array declaration is present. This is the reason why the project build does not meet ISO standards.

There are two solutions to this problem.

  1. Modify the matd.h header file to ensure that the C++ translation unit including apriltag.h complies with ISO standards during the build (this is the method I'm currently using).
  2. Ensure apriltag.h does not include or recursively include matd.h.

@zhaoxi-scut
Copy link
Author

zhaoxi-scut commented Nov 17, 2024

Oh, by the way, the environment of this perf test are as follows.

  • CPU: i5-12400F
  • OS: Ubuntu 22.04
  • Compiler: GNU GCC/G++ 11.4.0
  • Apriltag version: master (latest)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants