Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tests/device/cpu.cfa

    rd363634 rcf85f96  
    1717#include <fstream.hfa>
    1818#include <device/cpu.hfa>
     19#include <stdlib.hfa>
     20
     21#include <errno.h>
     22#include <stdio.h>
     23#include <string.h>
     24#include <unistd.h>
     25
    1926extern "C" {
     27        #include <dirent.h>
     28        #include <sys/types.h>
     29        #include <sys/stat.h>
    2030        #include <sys/sysinfo.h>
     31        #include <fcntl.h>
     32}
     33
     34// go through a directory calling fn on each file
     35static int iterate_dir( const char * path, void (*fn)(struct dirent * ent) ) {
     36        // open the directory
     37        DIR *dir = opendir(path);
     38        if(dir == 0p) { return ENOTDIR; }
     39
     40        // call fn for each
     41        struct dirent * ent;
     42        while ((ent = readdir(dir)) != 0p) {
     43                fn( ent );
     44        }
     45
     46        // no longer need this
     47        closedir(dir);
     48        return 0;
     49}
     50
     51// count the number of directories with the specified prefix
     52// the directories counted have the form '[prefix]N' where prefix is the parameter
     53// and N is an base 10 integer.
     54static int count_prefix_dirs(const char * path, const char * prefix) {
     55        // read the directory and find the cpu count
     56        // and make sure everything is as expected
     57        int max = -1;
     58        int count = 0;
     59        void lambda(struct dirent * ent) {
     60                // were are looking for prefixX, where X is a number
     61                // check that it starts with 'cpu
     62                char * s = strstr(ent->d_name, prefix);
     63                if(s == 0p) { return; }
     64                if(s != ent->d_name) { return; }
     65
     66                // check that the next part is a number
     67                s += strlen(prefix);
     68                char * end;
     69                long int val = strtol(s, &end, 10);
     70                if(*end != '\0' || val < 0) { return; }
     71
     72                // check that it's a directory
     73                if(ent->d_type != DT_DIR) { return; }
     74
     75                // it's a match!
     76                max = max(val, max);
     77                count++;
     78        }
     79        iterate_dir(path, lambda);
     80
     81        /* paranoid */ verifyf(count == max + 1, "Inconsistent %s count, counted %d, but max %s was %d", prefix, count, prefix, (int)max);
     82
     83        return count;
     84}
     85
     86// Count number of cache *indexes* in the system
     87// cache indexes are distinct from cache level as Data or Instruction cache
     88// can share a level but not an index
     89// PITFALL: assumes all cpus have the same indexes as cpu0
     90static int count_cache_indexes(void) {
     91        return count_prefix_dirs("/sys/devices/system/cpu/cpu0/cache", "index");
     92}
     93
     94// read information about a spcficic cache index/cpu file into the output buffer
     95static size_t read_cpuidxinfo_into(unsigned cpu, unsigned idx, const char * file, char * out, size_t out_len) {
     96        // Pick the file we want and read it
     97        char buf[128];
     98        /* paranoid */ __attribute__((unused)) int len =
     99        snprintf(buf, 128, "/sys/devices/system/cpu/cpu%u/cache/index%u/%s", cpu, idx, file);
     100        /* paranoid */ verifyf(len > 0, "Could not generate '%s' filename for cpu %u, index %u", file, cpu, idx);
     101
     102        int fd = open(buf, 0, O_RDONLY);
     103        /* paranoid */ verifyf(fd > 0, "Could not open file '%s'", buf);
     104
     105        ssize_t r = read(fd, out, out_len);
     106        /* paranoid */ verifyf(r > 0, "Could not read file '%s'", buf);
     107
     108        /* paranoid */ __attribute__((unused)) int ret =
     109        close(fd);
     110        /* paranoid */ verifyf(ret == 0, "Could not close file '%s'", buf);
     111
     112        out[r-1] = '\0';
     113        return r-1;
     114}
     115
     116unsigned find_idx() {
     117        int idxs = count_cache_indexes();
     118
     119        unsigned found_level = 0;
     120        unsigned found = -1u;
     121        for(i; idxs) {
     122                unsigned idx = idxs - 1 - i;
     123                char buf[32];
     124
     125                // Level is the cache level: higher means bigger and slower
     126                read_cpuidxinfo_into(0, idx, "level", buf, 32);
     127                char * end;
     128                unsigned long level = strtoul(buf, &end, 10);
     129                /* paranoid */ verifyf(level <= 250, "Cpu %u has more than 250 levels of cache, that doesn't sound right", 0);
     130                /* paranoid */ verify(*end == '\0');
     131
     132                if(found_level < level) {
     133                        found_level = level;
     134                        found = idx;
     135                }
     136        }
     137
     138        /* paranoid */ verify(found != -1u);
     139        return found;
    21140}
    22141
    23142int main() {
     143        //-----------------------------------------------------------------------
    24144        int ret1 = get_nprocs();
    25145        int ret2 = cpu_info.hthrd_count;
     
    31151        }
    32152
     153        //-----------------------------------------------------------------------
     154        // Make sure no one has the same self
     155        for(ime; cpu_info.hthrd_count) {
     156                unsigned me = cpu_info.llc_map[ime].self;
     157                {
     158                        unsigned s = cpu_info.llc_map[ime].start;
     159                        unsigned e = s + cpu_info.llc_map[ime].count;
     160                        if(me < s || me >= e) {
     161                                sout | "CPU" | ime | "outside of it's own map: " | s | "<=" | me | "<" | e;
     162                        }
     163                }
     164
     165
     166                for(ithem; cpu_info.hthrd_count) {
     167                        if(ime == ithem) continue;
     168
     169                        unsigned them = cpu_info.llc_map[ithem].self;
     170                        if(me == them) {
     171                                sout | "CPU" | ime | "has conflicting self id with" | ithem | "(" | me | ")";
     172                        }
     173                }
     174        }
     175
     176
     177        //-----------------------------------------------------------------------
     178        unsigned idx = find_idx();
     179        // For all procs check mapping is consistent
     180        for(cpu_me; cpu_info.hthrd_count) {
     181                char buf_me[32];
     182                size_t len_me = read_cpuidxinfo_into(cpu_me, idx, "shared_cpu_list", buf_me, 32);
     183                for(cpu_them; cpu_info.hthrd_count) {
     184                        if(cpu_me == cpu_them) continue;
     185                        char buf_them[32];
     186                        size_t len_them = read_cpuidxinfo_into(cpu_them, idx, "shared_cpu_list", buf_them, 32);
     187
     188                        bool match_file = len_them == len_me && 0 == strncmp(buf_them, buf_me, len_me);
     189                        bool match_info = cpu_info.llc_map[cpu_me].start == cpu_info.llc_map[cpu_them].start && cpu_info.llc_map[cpu_me].count == cpu_info.llc_map[cpu_them].count;
     190
     191                        if(match_file != match_info) {
     192                                sout | "CPU" | cpu_me | "and" | cpu_them | "have inconsitent file and cpu_info";
     193                                sout | cpu_me | ": <" | cpu_info.llc_map[cpu_me  ].start | "," | cpu_info.llc_map[cpu_me  ].count | "> '" | buf_me   | "'";
     194                                sout | cpu_me | ": <" | cpu_info.llc_map[cpu_them].start | "," | cpu_info.llc_map[cpu_them].count | "> '" | buf_them | "'";
     195                        }
     196                }
     197        }
    33198}
Note: See TracChangeset for help on using the changeset viewer.