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