1 #include "udev.h"
2 #include "global.h"
3 #include "cpu.h"
4 
read_file(char * path,int * len)5 char* read_file(char* path, int* len) {
6   int fd = open(path, O_RDONLY);
7 
8   if(fd == -1) {
9     return NULL;
10   }
11 
12   //File exists, read it
13   int bytes_read = 0;
14   int offset = 0;
15   int block = 128;
16   char* buf = emalloc(sizeof(char)*DEFAULT_FILE_SIZE);
17   memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE);
18 
19   while (  (bytes_read = read(fd, buf+offset, block)) > 0 ) {
20     offset += bytes_read;
21   }
22 
23   if (close(fd) == -1) {
24     return NULL;
25   }
26 
27   *len = offset;
28   return buf;
29 }
30 
get_freq_from_file(char * path)31 long get_freq_from_file(char* path) {
32   int filelen;
33   char* buf;
34   if((buf = read_file(path, &filelen)) == NULL) {
35     printWarn("Could not open '%s'", path);
36     return UNKNOWN_FREQ;
37   }
38 
39   char* end;
40   errno = 0;
41   long ret = strtol(buf, &end, 10);
42   if(errno != 0) {
43     printBug("strtol: %s", strerror(errno));
44     free(buf);
45     return UNKNOWN_FREQ;
46   }
47 
48   // We will be getting the frequency in KHz
49   // We consider it is an error if frequency is
50   // greater than 10 GHz or less than 100 MHz
51   if(ret > 10000 * 1000 || ret <  100 * 1000) {
52     printBug("Invalid data was read from file '%s': %ld\n", path, ret);
53     return UNKNOWN_FREQ;
54   }
55 
56   free(buf);
57 
58   return ret/1000;
59 }
60 
get_cache_size_from_file(char * path)61 long get_cache_size_from_file(char* path) {
62   int filelen;
63   char* buf;
64   if((buf = read_file(path, &filelen)) == NULL) {
65     printWarn("Could not open '%s'", path);
66     return -1;
67   }
68 
69   buf[filelen] = '\0'; // remove the K at the end
70 
71   char* end;
72   errno = 0;
73   long ret = strtol(buf, &end, 10);
74   if(errno != 0) {
75     printBug("strtol: %s", strerror(errno));
76     free(buf);
77     return -1;
78   }
79 
80   free(buf);
81 
82   return ret * 1024;
83 }
84 
get_max_freq_from_file(uint32_t core)85 long get_max_freq_from_file(uint32_t core) {
86   char path[_PATH_FREQUENCY_MAX_LEN];
87   sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_FREQUENCY, _PATH_FREQUENCY_MAX);
88   return get_freq_from_file(path);
89 }
90 
get_min_freq_from_file(uint32_t core)91 long get_min_freq_from_file(uint32_t core) {
92   char path[_PATH_FREQUENCY_MAX_LEN];
93   sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_FREQUENCY, _PATH_FREQUENCY_MIN);
94   return get_freq_from_file(path);
95 }
96 
get_l1i_cache_size(uint32_t core)97 long get_l1i_cache_size(uint32_t core) {
98   char path[_PATH_CACHE_MAX_LEN];
99   sprintf(path, "%s%s/cpu%d%s%s",  _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L1I, _PATH_CACHE_SIZE);
100   return get_cache_size_from_file(path);
101 }
102 
get_l1d_cache_size(uint32_t core)103 long get_l1d_cache_size(uint32_t core) {
104   char path[_PATH_CACHE_MAX_LEN];
105   sprintf(path, "%s%s/cpu%d%s%s",  _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L1D, _PATH_CACHE_SIZE);
106   return get_cache_size_from_file(path);
107 }
108 
get_l2_cache_size(uint32_t core)109 long get_l2_cache_size(uint32_t core) {
110   char path[_PATH_CACHE_MAX_LEN];
111   sprintf(path, "%s%s/cpu%d%s%s",  _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L2, _PATH_CACHE_SIZE);
112   return get_cache_size_from_file(path);
113 }
114 
get_l3_cache_size(uint32_t core)115 long get_l3_cache_size(uint32_t core) {
116   char path[_PATH_CACHE_MAX_LEN];
117   sprintf(path, "%s%s/cpu%d%s%s",  _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L3, _PATH_CACHE_SIZE);
118   return get_cache_size_from_file(path);
119 }
120 
get_num_caches_from_files(char ** paths,int num_paths)121 int get_num_caches_from_files(char** paths, int num_paths) {
122   int SHARED_MAP_MAX_LEN = 8 + 1;
123   int filelen;
124   char* buf;
125   uint32_t* shared_maps = emalloc(sizeof(uint32_t *) * num_paths);
126 
127   // 1. Read cpu_shared_map from every core
128   for(int i=0; i < num_paths; i++) {
129     if((buf = read_file(paths[i], &filelen)) == NULL) {
130       printWarn("Could not open '%s'", paths[i]);
131       return -1;
132     }
133 
134     if(filelen > SHARED_MAP_MAX_LEN) {
135       printBug("Shared map length is %d while the max is be %d", filelen, SHARED_MAP_MAX_LEN);
136       return -1;
137     }
138 
139     char* end;
140     errno = 0;
141     long ret = strtol(buf, &end, 16);
142     if(errno != 0) {
143       printBug("strtol: %s", strerror(errno));
144       free(buf);
145       return -1;
146     }
147 
148     shared_maps[i] = (uint32_t) ret;
149   }
150 
151   // 2. Count number of different masks; this is the number of caches
152   int num_caches = 0;
153   bool found = false;
154   uint32_t* unique_shared_maps = emalloc(sizeof(uint32_t *) * num_paths);
155   for(int i=0; i < num_paths; i++) unique_shared_maps[i] = 0;
156 
157   for(int i=0; i < num_paths; i++) {
158     for(int j=0; j < num_paths && !found; j++) {
159       if(shared_maps[i] == unique_shared_maps[j]) found = true;
160     }
161     if(!found) {
162       unique_shared_maps[num_caches] = shared_maps[i];
163       num_caches++;
164     }
165     found = false;
166   }
167 
168   return num_caches;
169 }
170 
get_num_caches_by_level(struct cpuInfo * cpu,uint32_t level)171 int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level) {
172   char** paths = emalloc(sizeof(char *) * cpu->topo->total_cores);
173   char* cache_path = NULL;
174 
175   if(level == 0) cache_path = _PATH_CACHE_L1I;
176   else if(level == 1) cache_path = _PATH_CACHE_L1D;
177   else if(level == 2) cache_path = _PATH_CACHE_L2;
178   else if(level == 3) cache_path = _PATH_CACHE_L3;
179   else {
180     printBug("Found invalid cache level to inspect: %d\n", level);
181     return -1;
182   }
183 
184   for(int i=0; i < cpu->topo->total_cores; i++) {
185     paths[i] = emalloc(sizeof(char) * _PATH_CACHE_MAX_LEN);
186     sprintf(paths[i], "%s%s/cpu%d%s%s",  _PATH_SYS_SYSTEM, _PATH_SYS_CPU, i, cache_path, _PATH_CACHE_SHARED_MAP);
187   }
188 
189   int ret = get_num_caches_from_files(paths, cpu->topo->total_cores);
190 
191   for(int i=0; i < cpu->topo->total_cores; i++)
192     free(paths[i]);
193   free(paths);
194 
195   return ret;
196 }
197