Re: [tip: sched/core] sched/topology: Compute sd_weight considering cpuset partitions

From: K Prateek Nayak

Date: Sat Mar 21 2026 - 11:17:25 EST


Hello Shrikanth,

On 3/21/2026 7:43 PM, Shrikanth Hegde wrote:
>> And more evidence - by default we have:
>>
>>    sched_domain size: 296
>>    offset of sd_span: 292
>>
>> sizeof() seems to account some sort of 4-byte padding for the struct which
>> pushes the offset of sd->span into the struct size.
>>
>> To resolve this, we can also do:
>>
>> diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h
>> index a1e1032426dc..48bea2f7f750 100644
>> --- a/include/linux/sched/topology.h
>> +++ b/include/linux/sched/topology.h
>> @@ -148,7 +148,7 @@ struct sched_domain {
>>        * by attaching extra space to the end of the structure,
>>        * depending on how many CPUs the kernel has booted up with)
>>        */
>> -    unsigned long span[];
>> +    unsigned long span[] __aligned(2 * sizeof(int));
>>   };
>
> Wouldn't that be susceptible to change in sched_domain somewhere in between?
> Right now, it maybe aligning to 296 since it is 8 byte aligned.
>
> But lets say someone adds a new int in between. Then size of sched_domain would be 300.
> but span would still be 296 since it 8 bit aligned?

So the official GCC specification for "Arrays of Length Zero" [1] says:

Although the size of a zero-length array is zero, an array member of
this kind may increase the size of the enclosing type as a result of
tail padding.

so you can either have:

struct sched_domain {
...
unsigned int span_length; /* 288 4 */
unsigned long span[]; /* 292 0 */

/* XXX 4 byte tail padding */

/* size: 296 */
}

or:

struct sched_domain {
...
unsigned int span_length; /* 288 4 */

/* XXX 4 bytes hole, try to pack */

unsigned long span[]; /* 296 0 */

/* size: 296 */
}

If the variable length array is aligned, there is no need for a tail
padding and in both cases, length of span[] is always 0.

[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

But ...

>
>>     static inline struct cpumask *sched_domain_span(struct sched_domain *sd)
>> ---
>>
>> and the kernel boots fine with the sd_span offset aligned with
>> sched_domain struct size:
>>
>>    sched_domain size: 296
>>    offset of sd_span: 296
>>
>>
>> So Peter, which solution do you prefer?
>>
>> 1. Doing cpumask_and() after the *sd = { ... } initialization. (or)
>>
>> 2. Align sd->span to an 8-byte boundary.
>>
>
> Only update sd_weight and leave everything as it was earlier?
>
> sd_weight = cpumask_and_weight(cpu_map, tl->mask(tl, cpu));

... I agree with you and Chenyu, that this approach is better since
padding and alignment is again dependent on the compiler.

Anyhow we do a cpumask_weight() for sd_weight, and cpumask_and_weight()
being the same complexity shouldn't add any more overhead.

While we are at it, we can also remove that "sd->span_weight" assignment
before the build_sched_groups() loop since we already have it here.

--
Thanks and Regards,
Prateek