Bug 66783

Summary: cairo-perf does not deal with cpus larger then 1024 well.
Product: cairo Reporter: Nathan Zimmer <nzimmer>
Component: generalAssignee: Chris Wilson <chris>
Status: RESOLVED MOVED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: normal    
Priority: medium    
Version: 1.12.14   
Hardware: Other   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:

Description Nathan Zimmer 2013-07-10 16:32:21 UTC
The function check_cpu_affinity (void) can return incorrect results.

This function is attempting to confirm that the process is only running on a single cpu.  On a large box it can report success where it should have failed.

For example if it has affinity with cpus 600, 1200 check_cpu_affinity will report it is ok when that true.

This issue is that CPU_SETSIZE on some distros is 1024, but the kernel is quite capable of handling 4096 cpus.

The code in question is here.

    cpu_set_t affinity

    for(i = 0, cpu_count = 0; i < CPU_SETSIZE; ++i) {
        if (CPU_ISSET(i, &affinity))
            ++cpu_count;
    }
Comment 1 Chris Wilson 2013-07-10 17:01:13 UTC
If CPU_SETSIZE doesn't match the value as used by the kernel, sched_getaffinity() is meant to return -EINVAL. Is that the case on your system?

I don't think check_cpu_affinity() is particularly relevant when benchmarking, the impact of thread placement is interesting to study, but it is unclear that actually suggesting a particular placement is beneficial. So I can either fixup check_cpu_affinity() to ignore EINVAL or simply move the warning into the README.
Comment 2 Nathan Zimmer 2013-07-10 19:36:20 UTC
Ah, you are correct I was misreading the code.

>If CPU_SETSIZE doesn't match the value as used by the kernel, sched_getaffinity() is meant >to return -EINVAL. Is that the case on your system?

They don't need to match but the user does need to provide enough space for the bitmask.
So it works fine on systems where CPU_SETSIZE is greater then or equal to the number of configured cpus.

I don't think ignoring a error status is wise.

If you don't think the check is needed that would be fine by me.

But if someone is insistent here are the two standard ways I found:

#ifdef _SC_NPROCESSORS_CONF
        int nrcpus = sysconf(_SC_NPROCESSORS_CONF);
        cpu_set_t * cpu_mask;
        cpu_mask = CPU_ALLOC(nrcpus);
        mask_size = CPU_ALLOC_SIZE(nrcpus);
        sched_getaffinity(0, mask_size, &cpu_mask);
        cpu_count = CPU_COUNT_S(mask_size, cpu_mask);
        CPU_FREE(cpu_mask);
#endif

or if someone has and aversion to _SC_NPROCESSORS_CONF

        int nrcpus = 1024;
realloc:
        cpus = CPU_ALLOC(nrcpus);
        size = CPU_ALLOC_SIZE(nrcpus);
        CPU_ZERO_S(size, cpus);

        if (sched_getaffinity(0, size, cpus)) {
                if( errno == EINVAL && nrcpus < (4096<<4) ) {
                        CPU_FREE(cpus);
                        nrcpus <= 1;
                        goto realloc;
                }
                fatal("sched_getaffinity", ERR_SYSCALL, "Can't get CPU info\n");
        }
        cpu_count = CPU_COUNT_S(size, cpus);
        CPU_FREE(cpus);
Comment 3 GitLab Migration User 2018-08-25 13:43:34 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/cairo/cairo/issues/161.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.