aboutsummaryrefslogtreecommitdiff
path: root/src/sysfs.c
blob: a6cc675b872838b78a83c3bc9e3b50e865eaf929 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sysfs.h"
#include "zenmonitor.h"

#define CPUD_MAX 512
struct bitset {
    guint bits[CPUD_MAX/32];
};

static int bitset_set(struct bitset *set, int id) {
    if (id < CPUD_MAX) {
        int v = (set->bits[id/32] >> (id & 31)) & 1;

        set->bits[id/32] |= 1 << (id & 31);
        return v;
    }
    return 1;
}

static int cmp_cpudev(const void *ap, const void *bp) {
    return ((struct cpudev *)ap)->cpuid - ((struct cpudev *)bp)->cpuid;
}

struct cpudev* get_cpu_dev_ids(void) {
    struct cpudev *cpu_dev_ids;
    gshort coreid, cpuid, siblingid;
    GDir *dir;
    const gchar *entry;
    gchar *filename, *buffer;
    gchar **cpusiblings;
    gchar **ptr;
    guint cores;
    gboolean found;
    struct bitset seen = { 0 };
    int i;

    cores = get_core_count();
    cpu_dev_ids = malloc(cores * sizeof (*cpu_dev_ids));
    for (i=0;i<cores;i++)
        cpu_dev_ids[i] = (struct cpudev) { -1, -1 };

    dir = g_dir_open(SYSFS_DIR_CPUS, 0, NULL);
    if (dir) {
        int i = 0;

        while ((entry = g_dir_read_name(dir))) {
            if (sscanf(entry, "cpu%hd", &cpuid) != 1) {
                continue;
            }

            found = FALSE;

            filename = g_build_filename(SYSFS_DIR_CPUS, entry, "topology", "core_id", NULL);
            if (g_file_get_contents(filename, &buffer, NULL, NULL)) {
                coreid = (gshort) atoi(buffer);

                g_free(filename);
                g_free(buffer);

                filename = g_build_filename(SYSFS_DIR_CPUS, entry, "topology", "thread_siblings_list", NULL);
                if (g_file_get_contents(filename, &buffer, NULL, NULL)) {
                    cpusiblings = g_strsplit(buffer, ",", -1);
                    found = TRUE;

                    // check whether cpu device is not for SMT thread sibling
                    for (ptr = cpusiblings; *ptr; ptr++) {
                        siblingid = (gshort) atoi(*ptr);

                        // let's save the cpu device with lower number
                        if (siblingid < cpuid)
                            cpuid = siblingid;

                        if (bitset_set(&seen, siblingid)) {
                            found = FALSE;
                        }
                    }
                    g_strfreev(cpusiblings);
                }
            }

            if (found && i < cores) {
                cpu_dev_ids[i++] = (struct cpudev) { coreid, cpuid };
            }

            g_free(filename);
            g_free(buffer);
        }
    }

    qsort(cpu_dev_ids, cores, sizeof(*cpu_dev_ids), cmp_cpudev);

    return cpu_dev_ids;
}