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

Add quirc_end_with_workarea() #96

Closed
wants to merge 1 commit into from
Closed

Conversation

yamt
Copy link
Contributor

@yamt yamt commented Mar 22, 2021

  • add a new variant of quirc_end() to allow users to specify
    the working memory for the flood filling logic
  • motivation: the dynamic stack usage with recursion is not
    easy to deal with. (for me)
    eg. malloc/free is easier than launching a temporary thread
    with a large stack.
  • implementation:
    • make flood filling logic iterative. (vs recursive)
      i basically tried one-to-one conversions here to avoid mistakes.
      probably it has a room for later improvements.
    • passes around the user-specified working memory for flood fill
  • possible downsides:
    • might have a negative impact on architectures with fast stack.
      eg. something with register-window
    • might have a negative impact on demand-paged stack

@yamt
Copy link
Contributor Author

yamt commented Mar 22, 2021

btw, i'm not quite happy with the name quirc_end_with_workarea. suggestions are welcome.

lib/identify.c Outdated
{
struct flood_fill_vars stack[FLOOD_FILL_MAX_DEPTH];

quirc_end_with_workarea(q, (void *)stack, sizeof(stack));
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: casting to void * here seems unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed. thank you

lib/identify.c Outdated
span_func_t func, void *user_data,
const struct workarea *wa)
{
struct flood_fill_vars *stack = wa->p;
Copy link
Collaborator

Choose a reason for hiding this comment

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

wa->p could have been be provided by the caller of quirc_end_with_workarea and thus we have no guarantee that it is compatible with struct flood_fill_vars * (alignment, pointer type).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed. thank you.

@kaworu
Copy link
Collaborator

kaworu commented Mar 28, 2021

Hello @yamt and thank you for the contribution! I'll defer to @dlbeer about the flood-fill related changes and possible impact on embedded.

* add a new variant of quirc_end() to allow users to specify
  the working memory for the flood filling logic
* motivation: the dynamic stack usage with recursion is not
  easy to deal with. (for me)
  eg. malloc/free is easier than launching a temporary thread
  with a large stack.
* implementation:
  * make flood filling logic iterative. (vs recursive)
    i basically tried one-to-one conversions here to avoid mistakes.
    probably it has a room for later improvements.
  * passes around the user-specified working memory for flood fill
* possible downsides:
  * might have a negative impact on architectures with fast stack.
    eg. something with register-window
  * might have a negative impact on demand-paged stack
@dlbeer
Copy link
Owner

dlbeer commented Mar 29, 2021

How big does a workarea need to be for the library to behave well on typical images? I'm guessing it's of the order of a thousand-ish entries?

I'm very much in favour of removing the recursion, but I wonder if the workarea could just be allocated with a static fixed (or #define'd) size in struct quirc? We already have a static buffer for grid decoding, and I'm guessing this wouldn't add significantly to the size.

@yamt
Copy link
Contributor Author

yamt commented Mar 29, 2021

How big does a workarea need to be for the library to behave well on typical images? I'm guessing it's of the order of a thousand-ish entries?

i was assuming that FLOOD_FILL_MAX_DEPTH was the value for the typical images. wasn't it?

I'm very much in favour of removing the recursion, but I wonder if the workarea could just be allocated with a static fixed (or #define'd) size in struct quirc? We already have a static buffer for grid decoding, and I'm guessing this wouldn't add significantly to the size.

depends on the typical size, it might make sense.

@dlbeer
Copy link
Owner

dlbeer commented Mar 29, 2021

FLOOD_FILL_MAX_DEPTH is probably an overestimate, and was there to prevent stack overflow with the recursive flood-fill. I suspect you can probably get away with less, since the flood-fill really only needs to work well enough to distinguish features like rings and capstones. Happy for you to experiment with this and pick out what you think is a reasonable value.

@yamt
Copy link
Contributor Author

yamt commented Mar 29, 2021

FLOOD_FILL_MAX_DEPTH is probably an overestimate, and was there to prevent stack overflow with the recursive flood-fill.

ok.

I suspect you can probably get away with less, since the flood-fill really only needs to work well enough to distinguish features like rings and capstones. Happy for you to experiment with this and pick out what you think is a reasonable value.

some of my colleagues might have some experiment results about this. let me ask them.

@yamt
Copy link
Contributor Author

yamt commented Mar 31, 2021

I suspect you can probably get away with less, since the flood-fill really only needs to work well enough to distinguish features like rings and capstones. Happy for you to experiment with this and pick out what you think is a reasonable value.

some of my colleagues might have some experiment results about this. let me ask them.

unfortunately, they don't seem to have much info to share.

@yamt
Copy link
Contributor Author

yamt commented Mar 31, 2021

@dlbeer

reading at the code, i think that the max depth should be something like (image_height_in_pixels / 3 * 2).

  • rings are the most stack consuming regions to fill.
  • they consumes the stack the most when they are rotated by about 45 degree. (the depth would be about 2 * height)
  • the max height of rings is about 1/3 of the image height.

as it's a proportion to the image resolution, i guess there's no one-size-fit-all value of the max depth.
how do you think?

@yamt
Copy link
Contributor Author

yamt commented Apr 2, 2021

reading at the code, i think that the max depth should be something like (image_height_in_pixels / 3 * 2).

i did quick experiments around this value and it seems working as i expected.
(in my case image_height_in_pixels=720)

i guess it makes sense to make quirc_resize() allocate the buffer with this size automatically using malloc().
how do you think?

{
/* ensure the alignment */

size_t align = sizeof(int); /* alignof(**stackp) */
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't seem to be a safe assumption to me, can you elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the structure only contains several int members.
i'm not aware of any arch where this is not safe.

uintptr_t p = (uintptr_t)wa->p;
uintptr_t aligned_p = (p + align - 1) / align * align;

*stackp = (struct flood_fill_vars *)aligned_p;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Even assuming proper alignment, formally we don't know whether the pointer is compatible with struct flood_fill_vars * correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if you mean C-language lawyer level of "formal", i guess you are right.

@yamt
Copy link
Contributor Author

yamt commented Apr 5, 2021

i guess it makes sense to make quirc_resize() allocate the buffer with this size automatically using malloc().

i submitted an alternative version which do this.
#100

@yamt
Copy link
Contributor Author

yamt commented Apr 15, 2021

i haven't noticed any issues with the alternative (#100) so far.
let me close this one.

@yamt yamt closed this Apr 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants