On 9/2/22 16:45, Ilya Maximets wrote:
> On 9/2/22 15:26, Dumitru Ceara wrote:
>> On 8/24/22 19:26, Ilya Maximets wrote:
>>> Filling arrays of switches and routers for load balancers
>>> one-by-one is not very efficient. Copying them in bulk
>>> allows to save a noticeable amount of time in setups with
>>> large load balancer groups.
>>>
>>> Signed-off-by: Ilya Maximets <[email protected]>
>>> ---
>>
>> The patch makes complete sense. I would change a few minor things, I
>> think. Please see below.
>>
>>> lib/lb.c | 16 ++++++++++------
>>> lib/lb.h | 8 ++++----
>>> northd/northd.c | 41 +++++++++++++++++++++++++++++------------
>>> 3 files changed, 43 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/lib/lb.c b/lib/lb.c
>>> index 7b0ed1abe..fe6070a40 100644
>>> --- a/lib/lb.c
>>> +++ b/lib/lb.c
>>> @@ -239,23 +239,27 @@ ovn_northd_lb_find(struct hmap *lbs, const struct
>>> uuid *uuid)
>>> }
>>>
>>> void
>>> -ovn_northd_lb_add_lr(struct ovn_northd_lb *lb, struct ovn_datapath *od)
>>> +ovn_northd_lb_add_lr(struct ovn_northd_lb *lb, size_t n,
>>> + struct ovn_datapath **ods)
>>> {
>>> - if (lb->n_allocated_nb_lr == lb->n_nb_lr) {
>>> + while (lb->n_allocated_nb_lr <= lb->n_nb_lr + n) {
>>> lb->nb_lr = x2nrealloc(lb->nb_lr, &lb->n_allocated_nb_lr,
>>> sizeof *lb->nb_lr);
>>> }
>>
>> Neat!
>>
>>> - lb->nb_lr[lb->n_nb_lr++] = od;
>>> + memcpy(&lb->nb_lr[lb->n_nb_lr], ods, n * sizeof *ods);
>>> + lb->n_nb_lr += n;
>>> }
>>>
>>> void
>>> -ovn_northd_lb_add_ls(struct ovn_northd_lb *lb, struct ovn_datapath *od)
>>> +ovn_northd_lb_add_ls(struct ovn_northd_lb *lb, size_t n,
>>> + struct ovn_datapath **ods)
>>> {
>>> - if (lb->n_allocated_nb_ls == lb->n_nb_ls) {
>>> + while (lb->n_allocated_nb_ls <= lb->n_nb_ls + n) {
>>> lb->nb_ls = x2nrealloc(lb->nb_ls, &lb->n_allocated_nb_ls,
>>> sizeof *lb->nb_ls);
>>> }
>>> - lb->nb_ls[lb->n_nb_ls++] = od;
>>> + memcpy(&lb->nb_ls[lb->n_nb_ls], ods, n * sizeof *ods);
>>> + lb->n_nb_ls += n;
>>> }
>>>
>>> void
>>> diff --git a/lib/lb.h b/lib/lb.h
>>> index 832ed31fb..d7bc28e18 100644
>>> --- a/lib/lb.h
>>> +++ b/lib/lb.h
>>> @@ -88,10 +88,10 @@ struct ovn_northd_lb_backend {
>>> struct ovn_northd_lb *ovn_northd_lb_create(const struct
>>> nbrec_load_balancer *);
>>> struct ovn_northd_lb * ovn_northd_lb_find(struct hmap *, const struct uuid
>>> *);
>>> void ovn_northd_lb_destroy(struct ovn_northd_lb *);
>>> -void
>>> -ovn_northd_lb_add_lr(struct ovn_northd_lb *lb, struct ovn_datapath *od);
>>> -void
>>> -ovn_northd_lb_add_ls(struct ovn_northd_lb *lb, struct ovn_datapath *od);
>>> +void ovn_northd_lb_add_lr(struct ovn_northd_lb *lb, size_t n,
>>> + struct ovn_datapath **ods);
>>> +void ovn_northd_lb_add_ls(struct ovn_northd_lb *lb, size_t n,
>>> + struct ovn_datapath **ods);
>>>
>>> struct ovn_controller_lb {
>>> const struct sbrec_load_balancer *slb; /* May be NULL. */
>>> diff --git a/northd/northd.c b/northd/northd.c
>>> index b66843581..c202d27d5 100644
>>> --- a/northd/northd.c
>>> +++ b/northd/northd.c
>>> @@ -3845,7 +3845,9 @@ struct ovn_lb_group {
>>> struct hmap_node hmap_node;
>>> struct uuid uuid;
>>> size_t n;
>>> - struct ovn_northd_lb *lbs[];
>>> + struct ovn_northd_lb **lbs;
>>> + size_t n_od;
>>> + struct ovn_datapath **ods;
>>> };
>>>
>>> static struct ovn_lb_group *
>>> @@ -3883,12 +3885,11 @@ build_lbs(struct northd_input *input_data, struct
>>> hmap *datapaths,
>>>
>>> NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH (nbrec_lb_group,
>>>
>>> input_data->nbrec_load_balancer_group_table) {
>>> - size_t size = sizeof *lb_group +
>>> - nbrec_lb_group->n_load_balancer * sizeof(struct ovn_northd_lb
>>> *);
>>> -
>>> - lb_group = xzalloc(size);
>>> + lb_group = xzalloc(sizeof *lb_group);
>>> lb_group->uuid = nbrec_lb_group->header_.uuid;
>>> lb_group->n = nbrec_lb_group->n_load_balancer;
>>> + lb_group->lbs = xzalloc(lb_group->n * sizeof *lb_group->lbs);
>>> + lb_group->ods = xzalloc(hmap_count(datapaths) * sizeof
>>> *lb_group->ods);
>>
>> In an unfortunate case when LB groups are used for a subset of datapaths
>> and the number of datapaths that don't use LB groups is significant then
>> this is inefficient. I'd go for x2nrealloc() below, when populating
>> 'lb_group->ods'.
>
> Maybe. OTOH, the number of LB groups is, likely, not that big, and the
> number of datapaths is also not that huge. 2n realloc will actually end
> up allocating more memory in a general case, I think. But I can change
> this part if you think otherwise. I just didn't want to introduce yet
> another variable to track the array size. And it will be 2 extra variables
> if we'll allocate separate arrays for switches and routers.
>
You're right, we probably will hit other issues before the size of the
array will become a problem if there are a lot of datapaths. I think
it's ok to leave it as is.
>>
>>>
>>> for (size_t i = 0; i < nbrec_lb_group->n_load_balancer; i++) {
>>> const struct uuid *lb_uuid =
>>> @@ -3910,19 +3911,25 @@ build_lbs(struct northd_input *input_data, struct
>>> hmap *datapaths,
>>> const struct uuid *lb_uuid =
>>> &od->nbs->load_balancer[i]->header_.uuid;
>>> lb = ovn_northd_lb_find(lbs, lb_uuid);
>>> - ovn_northd_lb_add_ls(lb, od);
>>> + ovn_northd_lb_add_ls(lb, 1, &od);
>>> }
>>>
>>> for (size_t i = 0; i < od->nbs->n_load_balancer_group; i++) {
>>> nbrec_lb_group = od->nbs->load_balancer_group[i];
>>> lb_group = ovn_lb_group_find(lb_groups,
>>> &nbrec_lb_group->header_.uuid);
>>> - for (size_t j = 0; j < lb_group->n; j++) {
>>> - ovn_northd_lb_add_ls(lb_group->lbs[j], od);
>>> - }
>>> + lb_group->ods[lb_group->n_od++] = od;
>>> }
>>> }
>>>
>>> + HMAP_FOR_EACH (lb_group, hmap_node, lb_groups) {
>>> + for (size_t j = 0; j < lb_group->n; j++) {
>>> + ovn_northd_lb_add_ls(lb_group->lbs[j], lb_group->n_od,
>>> + lb_group->ods);
>>> + }
>>> + lb_group->n_od = 0;
>>> + }
>>> +
>>> HMAP_FOR_EACH (od, key_node, datapaths) {
>>> if (!od->nbr) {
>>> continue;
>>> @@ -3932,7 +3939,7 @@ build_lbs(struct northd_input *input_data, struct
>>> hmap *datapaths,
>>> const struct uuid *lb_uuid =
>>> &od->nbr->load_balancer[i]->header_.uuid;
>>> lb = ovn_northd_lb_find(lbs, lb_uuid);
>>> - ovn_northd_lb_add_lr(lb, od);
>>> + ovn_northd_lb_add_lr(lb, 1, &od);
>>> build_lrouter_lb_ips(od, lb);
>>> }
>>>
>>> @@ -3940,12 +3947,20 @@ build_lbs(struct northd_input *input_data, struct
>>> hmap *datapaths,
>>> nbrec_lb_group = od->nbr->load_balancer_group[i];
>>> lb_group = ovn_lb_group_find(lb_groups,
>>> &nbrec_lb_group->header_.uuid);
>>> + lb_group->ods[lb_group->n_od++] = od;
>>> for (size_t j = 0; j < lb_group->n; j++) {
>>> - ovn_northd_lb_add_lr(lb_group->lbs[j], od);
>>> build_lrouter_lb_ips(od, lb_group->lbs[j]);
>>> }
>>> }
>>> }
>>> +
>>> + HMAP_FOR_EACH (lb_group, hmap_node, lb_groups) {
>>> + for (size_t j = 0; j < lb_group->n; j++) {
>>> + ovn_northd_lb_add_lr(lb_group->lbs[j], lb_group->n_od,
>>> + lb_group->ods);
>>> + }
>>> + lb_group->n_od = 0;
>>
>> This is a bit confusing. That's because we reuse the 'lb_group->ods'
>> array; we use it first for switches and then for routers. I think I'd
>> just add two array (like we do for 'struct ovn_northd_lb'). It's more
>> verbose but there's no ambiguity then.
>
> LB group will be destroyed and re-created, so we can avoid re-setting
> the value here. I was trying to avoid having too many variables.
> And since both are datapaths, we can re-use the same array and not
> re-allocate it twice. Either way is fine for me, but having one array
> is slightly more efficient. What do you think?
>
I think I'd prefer two variables. I don't think the performance hit is
visibile but it's up to you I guess. I'm ok either way in the end.
If there are no other changes to this patch then:
Acked-by: Dumitru Ceara <[email protected]>
>>
>>> + }
>>> }
>>>
>>> static void
>>> @@ -4130,7 +4145,7 @@ build_lswitch_lbs_from_lrouter(struct hmap
>>> *datapaths, struct hmap *lbs)
>>> }
>>> }
>>> if (!installed) {
>>> - ovn_northd_lb_add_ls(lb, od);
>>> + ovn_northd_lb_add_ls(lb, 1, &od);
>>> }
>>> if (lb->nlb) {
>>> od->has_lb_vip |= lb_has_vip(lb->nlb);
>>> @@ -15403,6 +15418,8 @@ northd_destroy(struct northd_data *data)
>>>
>>> struct ovn_lb_group *lb_group;
>>> HMAP_FOR_EACH_POP (lb_group, hmap_node, &data->lb_groups) {
>>> + free(lb_group->lbs);
>>> + free(lb_group->ods);
>>> free(lb_group);
>>> }
>>> hmap_destroy(&data->lb_groups);
>>
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev