1 /*
2
3 Copyright (C) 2008-2019 Michele Martone
4
5 This file is part of librsb.
6
7 librsb is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 librsb is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with librsb; see the file COPYING.
19 If not, see <http://www.gnu.org/licenses/>.
20
21 */
22 /* @cond INNERDOC */
23 /*!
24 * @file
25 * @author Michele Martone
26 * @brief Functions dumping system information to users.
27 * */
28
29 #include <unistd.h> /* sysconf */
30 #include "rsb_internals.h"
31 #include "rsb.h"
32 #ifdef RSB_HAVE_LIMITS_H
33 #include <limits.h> /* CHAR_BIT */
34 #endif /* RSB_HAVE_LIMITS_H */
35 #include <assert.h> /* assert */
36 #ifdef RSB_HAVE_MALLOC_H
37 #include <malloc.h> /* posix_memalign */
38 #endif /* RSB_HAVE_MALLOC_H */
39
40 #ifdef RSB_HAVE_TIMES_H
41 #include <sys/times.h>
42 #endif /* RSB_HAVE_TIMES_H */
43 #ifdef RSB_HAVE_SYS_SYSTEMCFG_H
44 #include <sys/systemcfg.h> /* for _H_SYSTEMCFG */
45 #endif /* RSB_HAVE_SYS_SYSTEMCFG_H */
46 #ifdef RSB_HAVE_SCHED_H
47 #include <sched.h> /* sched_getaffinity; FIXME: move to sys.c */
48 #include "rsb-config.h"
49 #endif /* RSB_HAVE_SCHED_H */
50
51 RSB_INTERNALS_COMMON_HEAD_DECLS
52
53 #ifdef _H_SYSTEMCFG
54 #if 0
55 from systemcfg.h :
56 extern struct {
57 int architecture; /* processor architecture */
58 int implementation; /* processor implementation */
59 int version; /* processor version */
60 int width; /* width (32 || 64) */
61 int ncpus; /* 1 = UP, n = n-way MP */
62 int cache_attrib; /* L1 cache attributes (bit flags) */
63 /* bit 0/1 meaning */
64 /* -------------------------------------*/
65 /* 31 no cache / cache present */
66 /* 30 separate I and D / combined */
67 int icache_size; /* size of L1 instruction cache */
68 int dcache_size; /* size of L1 data cache */
69 int icache_asc; /* L1 instruction cache associativity */
70 int dcache_asc; /* L1 data cache associativity */
71 int icache_block; /* L1 instruction cache block size */
72 int dcache_block; /* L1 data cache block size */
73 int icache_line; /* L1 instruction cache line size */
74 int dcache_line; /* L1 data cache line size */
75 int L2_cache_size; /* size of L2 cache, 0 = No L2 cache */
76 int L2_cache_asc; /* L2 cache associativity */
77 int tlb_attrib; /* TLB attributes (bit flags) */
78 /* bit 0/1 meaning */
79 /* -------------------------------------*/
80 /* 31 no TLB / TLB present */
81 /* 30 separate I and D / combined */
82 int itlb_size; /* entries in instruction TLB */
83 int dtlb_size; /* entries in data TLB */
84 int itlb_asc; /* instruction tlb associativity */
85 int dtlb_asc; /* data tlb associativity */
86 long long physmem; /* bytes of OS available memory */
87 ..
88 }_system_configuration;
89 #endif
90
aix_sys_info()91 static rsb_err_t aix_sys_info()
92 {
93 /*!
94 \ingroup internals
95 */
96 RSB_INFO("Working on an AIX system\n");
97 RSB_INFO("CPU : %ld \n",_system_configuration.ncpus);
98 RSB_INFO("cache_at :%ld \n",_system_configuration.cache_attrib);
99 RSB_INFO("L1 : %ld \n",_system_configuration.dcache_size);
100 RSB_INFO("L2 : %ld \n",_system_configuration.L2_cache_size);
101 RSB_INFO("MEM : %lld \n",_system_configuration.physmem);
102 }
103 #endif /* _H_SYSTEMCFG */
104
105
106
get_sysconf_cacheinfo(long * cpa,long * cpb,long * cpc,int cac,int cbc,int ccc,int cl)107 static rsb_err_t get_sysconf_cacheinfo( long *cpa, long *cpb, long *cpc, int cac, int cbc, int ccc, int cl)
108 {
109 /*!
110 \ingroup internals
111 */
112 *cpa = sysconf(cac);
113 *cpb = sysconf(cbc);
114 *cpc = sysconf(ccc);
115 if(*cpa<1 || *cpb < 1 || *cpc < 1)
116 RSB_INFO("sysconf() : no level %d cache\n",cl);
117 else
118 {
119 RSB_INFO("sysconf() : level %d cache size %ld \n",cl,*cpc);
120 RSB_INFO("sysconf() : level %d cache associativity %ld \n",cl,*cpa);
121 RSB_INFO("sysconf() : level %d cache line size %ld \n",cl,*cpb);
122 }
123 return RSB_ERR_NO_ERROR;
124 }
125
rsb_max_threads(void)126 static long rsb_max_threads(void)
127 {
128 /*!
129 * \ingroup gr_internals
130 *
131 * Just a user-oriented function.
132 *
133 * \return the maximum number of available hardware threads
134 *
135 * If on AIX, we use the native solution, as sysconf() gives values with are not usable as threads.
136 * */
137 #ifdef _H_SYSTEMCFG
138 return _system_configuration.ncpus;
139 #else /* _H_SYSTEMCFG */
140 #ifdef RSB_HAVE_SYSCONF
141 /*
142 * _SC_NPROCESSORS_ONLN : The number of processors currently online (available).
143 * _SC_NPROCESSORS_CONF : The number of processors configured.
144 */
145 //return sysconf(_SC_NPROCESSORS_CONF);
146 return sysconf(_SC_NPROCESSORS_ONLN);
147 #else /* RSB_HAVE_SYSCONF */
148 return 0; /* this should be regarded as an error */
149 #endif /* RSB_HAVE_SYSCONF */
150 #endif /* _H_SYSTEMCFG */
151 }
152
rsb__sys_info()153 rsb_err_t rsb__sys_info()
154 {
155 /*!
156 \ingroup internals
157 *
158 * A function printing out information about the system.
159 * It gives information for the user about the library configuration.
160 * It should be called after library initialization.
161 *
162 * \return an error code or RSB_ERR_NO_ERROR.
163 * TODO: move to sys.c
164 * */
165 rsb_err_t errval = RSB_ERR_NO_ERROR;
166
167 #if RSB_WITH_HWLOC
168 {
169 int i;
170 for(i=1;i<4;++i)
171 {
172 size_t sz = rsb__get_lnc_size_hwloc(i);
173 if(sz)
174 RSB_INFO("hwloc size of cache level %d: %zd\n",i,sz);
175 }
176 }
177 #endif /* RSB_WITH_HWLOC */
178
179 RSB_INFO("detected max available cores/threads : %ld\n",(long int)rsb_max_threads());
180 #if RSB_WANT_OMP_RECURSIVE_KERNELS
181 #pragma omp parallel
182 {
183 RSB_INFO("detected max OpenMP procs : %ld\n",(long int)omp_get_num_procs());
184 }
185 #endif /* RSB_WANT_OMP_RECURSIVE_KERNELS */
186 RSB_INFO("detected %ld levels of cache\n",(long int)rsb__get_cache_levels_num());
187 {
188 int i;
189 for(i=1;i <= rsb__get_cache_levels_num();++i)
190 RSB_INFO("L%d size: %ld \n",i,(long int)rsb__get_lnc_size(i));
191 }
192
193 #ifdef _H_SYSTEMCFG
194 aix_sys_info();
195 #endif /* _H_SYSTEMCFG */
196
197 // RSB_INFO("LL size: %ld \n",(long int)rsb__get_lastlevel_c_size());
198
199 #ifndef RSB_HAVE_SYSCONF
200 RSB_INFO("sysconf() not available\n");
201 #else /* RSB_HAVE_SYSCONF */
202 // RSB_INFO("detected %ld levels of cache\n",(long int)rsb__get_cache_levels_num());
203 #endif /* RSB_HAVE_SYSCONF */
204 {
205 #ifdef RSB_HAVE_SYSCONF
206 long int pagesize = 0;
207 long int mem_pages = 0;
208 size_t tot_mem = 0;
209 #if defined(PAGESIZE)
210 pagesize = sysconf(PAGESIZE);
211 #elif defined(_SC_PAGESIZE)
212 pagesize = sysconf(_SC_PAGESIZE);
213 #elif defined(PAGE_SIZE)
214 pagesize = sysconf(PAGE_SIZE);
215 #else /* PAGE_SIZE */
216 #endif /* PAGE_SIZE */
217 if( pagesize)RSB_INFO("sysconf() : %ld bytes per pagesize\n",pagesize);
218 if(!pagesize)RSB_INFO("sysconf() available, PAGESIZE _SC_PAGESIZE PAGE_SIZE undefined\n");
219
220 /*
221 _SC_AVPHYS_PAGES : The number of currently available pages of physical memory.
222 _SC_PHYS_PAGES : The number of pages of physical memory.
223 */
224 #if defined(_SC_PHYS_PAGES)
225 mem_pages = sysconf(_SC_PHYS_PAGES);
226 #else /* _SC_PHYS_PAGES */
227 #endif /* _SC_PHYS_PAGES */
228 tot_mem = (size_t)mem_pages;
229 tot_mem *= (size_t)pagesize;
230 if( mem_pages)RSB_INFO("sysconf() : %zu physical pages\n",(size_t)mem_pages);
231 if(!mem_pages)RSB_INFO("sysconf() available, _SC_PHYS_PAGES undefined\n");
232 if( mem_pages && pagesize)RSB_INFO("sysconf() : %zu bytes (%zu MB) of physical memory\n",tot_mem,(tot_mem)/(1024*1024));
233 #if defined(_SC_AVPHYS_PAGES)
234 RSB_INFO("sysconf() : %zu available (free) physical pages\n",(size_t)sysconf(_SC_AVPHYS_PAGES));
235 RSB_INFO("sysconf() : %zu available (free) physical memory\n",(size_t)sysconf(_SC_AVPHYS_PAGES)*pagesize);
236 #endif /* _SC_AVPHYS_PAGES */
237 #endif /* RSB_HAVE_SYSCONF */
238 }
239 {
240 #ifdef RSB_HAVE_SYSCONF
241 long int sc_nprocessors_conf;
242 long int sc_nprocessors_onln;
243 /*
244 * _SC_NPROCESSORS_ONLN : The number of processors currently online (available).
245 * _SC_NPROCESSORS_CONF : The number of processors configured.
246 */
247 sc_nprocessors_conf = sysconf(_SC_NPROCESSORS_CONF);
248 sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
249 RSB_INFO("sysconf() , processors : %ld\n",sc_nprocessors_conf);
250 RSB_INFO("sysconf() , processors online : %ld\n",sc_nprocessors_onln);
251 #endif /* RSB_HAVE_SYSCONF */
252 }
253 #ifdef RSB_HAVE_SYSCONF
254 {
255 #ifdef _SC_LEVEL1_DCACHE_SIZE
256 long int c1a,c1b,c1c;
257 c1a = sysconf(_SC_LEVEL1_DCACHE_ASSOC);
258 c1b = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
259 c1c = sysconf(_SC_LEVEL1_DCACHE_SIZE);
260 get_sysconf_cacheinfo(&c1a,&c1b,&c1c,_SC_LEVEL1_DCACHE_ASSOC,_SC_LEVEL1_DCACHE_LINESIZE,_SC_LEVEL1_DCACHE_SIZE,1);
261 #else /* _SC_LEVEL1_DCACHE_SIZE */
262 RSB_INFO("sysconf() implementation obsolete: no L%d cache info\n",1);
263 #endif /* _SC_LEVEL1_DCACHE_SIZE */
264 }
265 {
266 #ifdef _SC_LEVEL2_CACHE_SIZE
267 long int c2a,c2b,c2c;
268 c2a = sysconf(_SC_LEVEL2_CACHE_ASSOC);
269 c2b = sysconf(_SC_LEVEL2_CACHE_LINESIZE);
270 c2c = sysconf(_SC_LEVEL2_CACHE_SIZE);
271 get_sysconf_cacheinfo(&c2a,&c2b,&c2c,_SC_LEVEL2_CACHE_ASSOC,_SC_LEVEL2_CACHE_LINESIZE,_SC_LEVEL2_CACHE_SIZE,2);
272 #else /* _SC_LEVEL2_CACHE_SIZE */
273 RSB_INFO("sysconf() implementation obsolete: no L%d cache info\n",2);
274 #endif /* _SC_LEVEL2_CACHE_SIZE */
275 }
276 {
277 #ifdef _SC_LEVEL3_CACHE_SIZE
278 long int c3a,c3b,c3c;
279 c3a = sysconf(_SC_LEVEL3_CACHE_ASSOC);
280 c3b = sysconf(_SC_LEVEL3_CACHE_LINESIZE);
281 c3c = sysconf(_SC_LEVEL3_CACHE_SIZE);
282 get_sysconf_cacheinfo(&c3a,&c3b,&c3c,_SC_LEVEL3_CACHE_ASSOC,_SC_LEVEL3_CACHE_LINESIZE,_SC_LEVEL3_CACHE_SIZE,3);
283 #else /* _SC_LEVEL3_CACHE_SIZE */
284 RSB_INFO("sysconf() implementation obsolete: no L%d cache info\n",3);
285 #endif /* _SC_LEVEL3_CACHE_SIZE */
286 }
287 {
288 #ifdef _SC_LEVEL4_CACHE_SIZE
289 long int c4a,c4b,c4c;
290 c4a = sysconf(_SC_LEVEL4_CACHE_ASSOC);
291 c4b = sysconf(_SC_LEVEL4_CACHE_LINESIZE);
292 c4c = sysconf(_SC_LEVEL4_CACHE_SIZE);
293 get_sysconf_cacheinfo(&c4a,&c4b,&c4c,_SC_LEVEL4_CACHE_ASSOC,_SC_LEVEL4_CACHE_LINESIZE,_SC_LEVEL4_CACHE_SIZE,4);
294 #else /* _SC_LEVEL4_CACHE_SIZE */
295 RSB_INFO("sysconf() implementation obsolete: no L%d cache info\n",4);
296 #endif /* _SC_LEVEL4_CACHE_SIZE */
297 }
298 #endif /* RSB_HAVE_SYSCONF */
299 #ifdef CHAR_BIT
300 /* It should happen, but it could not. */
301 RSB_ASSERT(CHAR_BIT==sizeof(char)*8);
302
303 /* It should not happen, but it could. */
304 if(CHAR_BIT!=8)
305 {
306 RSB_DO_ERROR_CUMULATE(errval,RSB_ERR_INTERNAL_ERROR);
307 RSB_INFO("%d bits per byte! This is catastrophic.\n",CHAR_BIT);
308 }
309 else
310 RSB_INFO("8 bits per byte. Good.\n");
311 #else /* CHAR_BIT */
312 RSB_INFO("We have no information on bits per byte. Beware!\n");
313 #endif /* CHAR_BIT */
314 #if 1
315 {
316 long cbbs = rsb__get_cache_block_byte_size();
317 if(cbbs)
318 RSB_STDERR("cache block size : %ld \n",cbbs);
319 else
320 RSB_STDERR("cache block size unknown (detected %ld: this is a problem!)\n",cbbs);
321 }
322 #endif
323 #ifdef INT_MAX
324 RSB_INFO("SHRT_MAX : %hd\n",(short)SHRT_MAX);
325 RSB_INFO("SHRT_MIN : %hd\n",(short)SHRT_MIN);
326 RSB_INFO("USHRT_MAX : %hu\n",(unsigned short)USHRT_MAX);
327 RSB_INFO("INT_MIN : %d\n",(int)INT_MIN);
328 RSB_INFO("INT_MAX : %d\n",(int)INT_MAX);
329 RSB_INFO("UINT_MAX : %u\n",(unsigned)UINT_MAX);
330 RSB_INFO("LONG_MAX : %ld\n",(long int)LONG_MAX);
331 RSB_INFO("LONG_MIN : %ld\n",(long int)LONG_MIN);
332 #ifdef ULONG_MAX
333 RSB_INFO("ULONG_MAX : %lu\n",(long unsigned)ULONG_MAX);
334 #else /* ULONG_MAX */
335 RSB_INFO("ULONG_MAX : undefined\n");
336 #endif /* ULONG_MAX */
337 #ifdef LLONG_MAX
338 RSB_INFO("LLONG_MAX : %lld\n",(long long int)LLONG_MAX);
339 #else /* LLONG_MAX */
340 RSB_INFO("LLONG_MAX : undefined\n");
341 #endif /* LLONG_MAX */
342 #ifdef LLONG_MIN
343 RSB_INFO("LLONG_MIN : %lld\n",(long long int)LLONG_MIN);
344 #else /* LLONG_MIN */
345 RSB_INFO("LLONG_MIN : undefined\n");
346 #endif /* LLONG_MIN */
347 #ifdef ULLONG_MAX
348 RSB_INFO("ULLONG_MAX : %llu\n",(long long unsigned)ULLONG_MAX);
349 #else /* ULLONG_MAX */
350 RSB_INFO("ULLONG_MAX : undefined\n");
351 #endif /* ULLONG_MAX */
352 #else /* INT_MAX */
353 RSB_INFO("INT_MAX : undefined\n");
354 #endif /* INT_MAX */
355 RSB_INFO("RSB_MARKER_COO_VALUE : %llu\n",(long long unsigned)RSB_MARKER_COO_VALUE);
356 RSB_INFO("RSB_MARKER_NNZ_VALUE : %llu\n",(long long unsigned)RSB_MARKER_NNZ_VALUE);
357 RSB_INFO("RSB_SUBM_IDX_MARKER : %llu\n",(long long unsigned)RSB_SUBM_IDX_MARKER);
358 RSB_INFO("RSB_MAX_ALLOCATABLE_MEMORY_CHUNK: %llu\n",(long long unsigned)RSB_MAX_ALLOCATABLE_MEMORY_CHUNK);
359
360 RSB_INFO("timing min delta (if negative, don't complain with us) : %lg s\n", rsb__timer_sanity());
361 RSB_INFO("timing granularity : %lg s\n", rsb__timer_granularity());
362 #if defined(RSB_CFLAGS)
363 RSB_INFO("CFLAGS : %s\n",RSB_CFLAGS);
364 #else /* RSB_CFLAGS */
365 RSB_INFO("no CFLAGS info\n");
366 #endif /* RSB_CFLAGS */
367 #if defined(RSB_CC)
368 RSB_INFO("CC : %s\n",RSB_CC);
369 #else /* RSB_CC */
370 RSB_INFO("no CC info\n");
371 #endif /* RSB_CC */
372 #ifdef RSB_HAVE_SCHED_H
373 #ifdef RSB_HAVE_SCHED_GETAFFINITY
374 #ifdef _GNU_SOURCE
375 {
376 size_t num_cpus = CPU_SETSIZE;
377 cpu_set_t cpuset;
378 CPU_ZERO(&cpuset);
379 if(1)
380 {
381 int sgar = 0;
382
383 if( (sgar = sched_getaffinity(0, num_cpus, &cpuset)) != 0 )
384 {
385 RSB_INFO("sched_getaffinity error : %d\n",sgar);
386 }
387 else
388 {
389 RSB_INFO("sched_getaffinity's CPU_COUNT() of set: %d\n", CPU_COUNT_S(CPU_ALLOC_SIZE(1), &cpuset));
390 RSB_INFO("sched_getaffinity runnable : %zd\n",CPU_COUNT(&cpuset));
391 }
392 }
393 }
394 #endif /* _GNU_SOURCE */
395 #endif /* RSB_HAVE_SCHED_H */
396 #endif /* RSB_HAVE_SCHED_GETAFFINITY */
397 {
398 rsb_char_t usmhib[RSB_MAX_LINE_LENGTH];
399 RSB_INFO("memhinfo : %s\n",rsb__get_mem_hierarchy_info_string(usmhib));
400 }
401 RSB_INFO("detected free memory : %zd\n",(size_t)rsb__sys_free_system_memory());
402 RSB_INFO("detected total memory : %zd\n",(size_t)rsb__sys_total_system_memory());
403
404 {
405 rsb_nnz_idx_t *p = NULL;
406 rsb_nnz_idx_t n, i, maxtries = RSB_MAX_MATRIX_NNZ, res = 0, cookie = 0, tries, v, mintries = RSB_CONST_MIN_TIMES_FOR_MICRO_BENCHMARK;
407 n = 4*(rsb__get_lastlevel_c_size()/sizeof(rsb_nnz_idx_t));
408 if(n<2)goto failed;
409 p = rsb__malloc(sizeof(rsb_nnz_idx_t)*n);
410 if(!p)goto failed;
411 v = 1;
412 while(2*v <= n)v *= 2;
413 --v;
414 for(i=0;i<n;++i)p[i] = i;
415 while((v/2)>1)
416 {
417 rsb_time_t mtl = RSB_CONST_IMPOSSIBLY_BIG_TIME,mtb = RSB_CONST_IMPOSSIBLY_BIG_TIME,bt,mbt = RSB_CONST_TIME_FOR_MICRO_BENCHMARK,tt=0;
418 for(tt=0,tries=0;tries<mintries || (tt<mbt && tries<maxtries);++tries)
419 {
420 /* NOTE: we are not interested in flushing the cache, here */
421 bt = - rsb_time();
422 cookie += rsb__seek_nnz_idx_t(p,v,n);
423 bt += rsb_time();
424 mtb = RSB_MIN(mtb,bt);
425 tt += bt;
426 bt = - rsb_time();
427 cookie += rsb__seek_nnz_idx_t_linear(p,v,n);
428 bt += rsb_time();
429 mtl = RSB_MIN(mtl,bt);
430 tt += bt;
431 }
432 res = cookie;
433 RSB_INFO("for array sized %d elems, took %g s for linear search and %g s for binary search for element %d, in %d tries, for a total of %f s (ignore this:%d)\n", n,mtl,mtb,v,tries,tt,res);
434 v = v/2;
435 }
436 failed:
437 RSB_CONDITIONAL_FREE(p);
438 } errval = rsb__dump_system_performance_summary();
439
440 goto err;
441 err:
442 RSB_DO_ERR_RETURN(errval)
443 }
444
445 /* @endcond */
446