calibrator.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. /*
  2. * Calibrator v0.9e
  3. * by Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/Calibrator/
  4. *
  5. * All rights reserved.
  6. * No warranties.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above notice, this list
  13. * of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above notice, this
  15. * list of conditions and the following disclaimer in the documentation
  16. * and/or other materials provided with the distribution.
  17. * 3. All advertising materials mentioning features or use of this software
  18. * must display the following acknowledgement:
  19. * This product includes software developed by
  20. * Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/.
  21. * 4. Any publication of result obtained by use of this software must
  22. * display a reference as follows:
  23. * Results produced by Calibrator v0.9e
  24. * (Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/)
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS'' AND
  27. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  36. * THE POSSIBILITY OF SUCH DAMAGE.
  37. */
  38. /*
  39. #include <unistd.h>
  40. */
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include <math.h>
  44. #include <string.h>
  45. #include <stdarg.h>
  46. #define VERSION "0.9e"
  47. #define NUMLOADS 100000
  48. #define REDUCE 10
  49. #define NUMTRIES 3
  50. #define MINRANGE 1024
  51. #define MAXLEVELS 9
  52. #define LENPLATEAU 3
  53. #define EPSILON1 0.1
  54. /* #define EPSILON3 2.0 */
  55. /* #define EPSILON2 0.04 */
  56. #define EPSILON4 1.0
  57. #define MIN(a,b) (a<b?a:b)
  58. #define MAX(a,b) (a>b?a:b)
  59. #define NOABS(x) ((dbl)x)
  60. #define FABS fabs
  61. #define lng long
  62. #define dbl float
  63. lng MINTIME = 10000;
  64. #ifdef WIN32
  65. #include <Windows.h>
  66. /* #define MINTIME 100000 */
  67. size_t getpagesize() { return 4096; }
  68. lng oldtp = 0;
  69. lng now(void)
  70. {
  71. lng tp = (lng)timeGetTime();
  72. if (oldtp == 0) {
  73. /* timeBeginPeriod(1); */
  74. tp += 11;
  75. while ((lng)timeGetTime() <= tp) ;
  76. oldtp = tp = (lng)timeGetTime();
  77. }
  78. return (lng)((tp - oldtp) * (lng)1000);
  79. }
  80. #else
  81. #include <sys/time.h>
  82. /* #define MINTIME 10000 */
  83. struct timeval oldtp = { 0 };
  84. lng now(void)
  85. {
  86. struct timeval tp;
  87. gettimeofday(&tp, 0);
  88. if (oldtp.tv_sec == 0 && oldtp.tv_usec == 0) {
  89. oldtp = tp;
  90. }
  91. return (lng)( (lng)(tp.tv_sec - oldtp.tv_sec ) * (lng)1000000 +
  92. (lng)(tp.tv_usec - oldtp.tv_usec) );
  93. }
  94. #endif
  95. void ErrXit(char *format, ...) {
  96. va_list ap;
  97. char s[1024];
  98. va_start(ap,format);
  99. vsprintf(s, format, ap);
  100. va_end(ap);
  101. fprintf(stderr, "\n! %s !\n", s);
  102. fflush(stderr);
  103. exit(1);
  104. }
  105. lng round(dbl x)
  106. {
  107. return (lng)(x + 0.5);
  108. }
  109. char last(char *s)
  110. {
  111. while (*s++);
  112. return (s[-2]);
  113. }
  114. lng bytes(char *s)
  115. {
  116. lng n = atoi(s);
  117. if ((last(s) == 'k') || (last(s) == 'K'))
  118. n *= 1024;
  119. if ((last(s) == 'm') || (last(s) == 'M'))
  120. n *= (1024 * 1024);
  121. if ((last(s) == 'g') || (last(s) == 'G'))
  122. n *= (1024 * 1024 * 1024);
  123. return (n);
  124. }
  125. #define NSperIt(t) (((dbl)(t)) / (((dbl)NUMLOADS) / 1000.0))
  126. #define CYperIt(t) (((dbl)((t) * MHz)) / ((dbl)NUMLOADS))
  127. long use_result_dummy; /* !static for optimizers. */
  128. void use_pointer(void *result) { use_result_dummy += (long)result; }
  129. lng loads(char *array, lng range, lng stride, lng MHz, FILE *fp, int delay)
  130. {
  131. register char **p = 0;
  132. lng i, j=1, tries;
  133. lng time, best = 2000000000;
  134. fprintf(stderr, "\r%11ld %11ld %11ld", range, stride, range/stride);
  135. fflush(stderr);
  136. /*
  137. for (i = stride; i < range; i += stride) {
  138. p = (char **)&array[i];
  139. *p = &array[i - stride];
  140. }
  141. p = (char **)&array[0];
  142. *p = &array[i - stride];
  143. */
  144. for (i = stride; i < range; i += stride);
  145. i -= stride;
  146. for (; i >= 0; i -= stride) {
  147. char *next;
  148. p = (char **)&array[i];
  149. if (i < stride) {
  150. next = &array[range - stride];
  151. } else {
  152. next = &array[i - stride];
  153. }
  154. *p = next;
  155. }
  156. #define ONE p = (char **)*p;
  157. #define TEN ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE
  158. #define HUNDRED TEN TEN TEN TEN TEN TEN TEN TEN TEN TEN
  159. /*
  160. #define THOUSAND HUNDRED HUNDRED HUNDRED HUNDRED HUNDRED \
  161. HUNDRED HUNDRED HUNDRED HUNDRED HUNDRED
  162. */
  163. #define FILL p++; p--; p++; p--; p++; p--; p++; p--; p++; p--;
  164. #define ONEx p = (char **)*p; \
  165. FILL FILL FILL FILL FILL FILL FILL FILL FILL FILL
  166. /*
  167. #define TENx ONEx ONEx ONEx ONEx ONEx ONEx ONEx ONEx ONEx ONEx
  168. #define HUNDREDx TENx TENx TENx TENx TENx TENx TENx TENx TENx TENx
  169. */
  170. if(delay) for (tries = 0; tries < NUMTRIES; ++tries) {
  171. i = (j * NUMLOADS) / REDUCE;
  172. time = now();
  173. while (i > 0) {
  174. ONEx
  175. i -= 1;
  176. }
  177. time = now() - time;
  178. use_pointer((void *)p);
  179. if (time <= MINTIME) {
  180. j *= 2;
  181. tries--;
  182. } else {
  183. time *= REDUCE;
  184. time /= j;
  185. if (time < best) {
  186. best = time;
  187. }
  188. }
  189. } else for (tries = 0; tries < NUMTRIES; ++tries) {
  190. i = (j * NUMLOADS);
  191. time = now();
  192. while (i > 0) {
  193. HUNDRED
  194. i -= 100;
  195. }
  196. time = now() - time;
  197. use_pointer((void *)p);
  198. if (time <= MINTIME) {
  199. j *= 2;
  200. tries--;
  201. } else {
  202. time /= j;
  203. if (time < best) {
  204. best = time;
  205. }
  206. }
  207. }
  208. fprintf(stderr, " %11ld %11ld", best*j, best);
  209. fflush(stderr);
  210. if (fp) {
  211. fprintf(fp, " %06ld %05.1f %05.1f"
  212. ,best /* elapsed time [microseconds] */
  213. ,NSperIt(best) /* nanoseconds per iteration */
  214. ,CYperIt(best) /* clocks per iteration */
  215. );
  216. fflush(fp);
  217. }
  218. return best;
  219. }
  220. lng** runCache(char *array, lng maxrange, lng minstride, lng MHz, FILE *fp, lng *maxstride)
  221. {
  222. lng i, r, x, y, z, range = maxrange, stride = minstride / 2;
  223. dbl f = 0.25;
  224. lng last, time = 0, **result;
  225. lng pgsz = getpagesize();
  226. int delay;
  227. if (*maxstride) {
  228. fprintf(stderr, "analyzing cache latency...\n");
  229. } else {
  230. fprintf(stderr, "analyzing cache throughput...\n");
  231. }
  232. fprintf(stderr, " range stride spots brutto- netto-time\n");
  233. fflush(stderr);
  234. if (!(*maxstride)) {
  235. do {
  236. stride *= 2;
  237. last = time;
  238. time = loads(array, range, stride, MHz, 0, 0);
  239. if (!time)
  240. ErrXit("runCache: 'loads(%x(array), %ld(range), %ld(stride), %ld(MHz), 0(fp), 0(delay))` returned elapsed time of 0us",
  241. array, range, stride, MHz);
  242. #ifdef EPSILON1
  243. } while (((fabs(time - last) / (dbl)time) > EPSILON1) && (stride <= (maxrange / 2)));
  244. #endif
  245. #ifdef EPSILON3
  246. } while ((fabs(CYperIt(time) - CYperIt(last)) > EPSILON3) && (stride <= (maxrange / 2)));
  247. #endif
  248. *maxstride = stride;
  249. delay = 0;
  250. } else if (*maxstride < 0) {
  251. *maxstride *= -1;
  252. delay = 0;
  253. } else {
  254. delay = 1;
  255. }
  256. for (r = MINRANGE, y = 1; r <= maxrange; r *= 2) {
  257. for (i = 3; i <= 5; i++) {
  258. range = r * f * i;
  259. if ((*maxstride <= range) && (range <= maxrange)) {
  260. for (stride = *maxstride, x = 1; stride >= minstride; stride /= 2, x++) {
  261. }
  262. y++;
  263. }
  264. }
  265. }
  266. if (!(result = (lng**)malloc(y * sizeof(lng*))))
  267. ErrXit("runCache: 'result = malloc(%ld)` failed", y * sizeof(lng*));
  268. for (z = 0; z < y; z++) {
  269. if (!(result[z] = (lng*)malloc(x * sizeof(lng))))
  270. ErrXit("runCache: 'result[%ld] = malloc(%ld)` failed", z, x * sizeof(lng));
  271. memset(result[z], 0, x * sizeof(lng));
  272. }
  273. result[0][0] = (y << 24) | x;
  274. fprintf(fp, "# Calibrator v%s\n", VERSION);
  275. fprintf(fp, "# (by Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/)\n");
  276. for (r = MINRANGE, y = 1; r <= maxrange; r *= 2) {
  277. for (i = 3; i <= 5; i++) {
  278. range = r * f * i;
  279. if ((*maxstride <= range) && (range <= maxrange)) {
  280. result[y][0] = range;
  281. fprintf(fp, "%08.1f %05ld"
  282. ,range / 1024.0 /* range in KB */
  283. ,range / pgsz /* # pages covered */
  284. );
  285. fflush(fp);
  286. for (stride = *maxstride, x = 1; stride >= minstride; stride /= 2, x++) {
  287. if (!result[0][x]) {
  288. result[0][x] = stride;
  289. }
  290. fprintf(fp, " %03ld %09ld %08.1f"
  291. ,stride /* stride */
  292. ,range / stride /* # spots accessed */
  293. ,((dbl)NUMLOADS) / ((dbl)(range / stride)) /* # accesses per spot */
  294. );
  295. fflush(fp);
  296. result[y][x] = loads(array, range, stride, MHz, fp, delay);
  297. }
  298. fprintf(fp, "\n");
  299. fflush(fp);
  300. y++;
  301. }
  302. }
  303. }
  304. fprintf(stderr, "\n\n");
  305. fflush(stderr);
  306. return result;
  307. }
  308. lng** runTLB(char *array, lng maxrange, lng minstride, lng shift, lng mincachelines, lng MHz, FILE *fp, lng *maxstride)
  309. {
  310. lng i, x, y, z, stride, minspots, maxspots, p;
  311. lng range = maxrange, s = minstride / 2, spots = mincachelines / 2;
  312. dbl f = 0.25;
  313. lng tmax, smin, xmin, last, time = 0, **result;
  314. lng pgsz = getpagesize();
  315. int delay;
  316. fprintf(stderr, "analyzing TLB latency...\n");
  317. fprintf(stderr, " range stride spots brutto- netto-time\n");
  318. fflush(stderr);
  319. if (!(*maxstride)) {
  320. do {
  321. s *= 2;
  322. stride = s + shift;
  323. range = stride * spots;
  324. last = time;
  325. time = loads(array, range, stride, MHz, 0, 0);
  326. if (!time)
  327. ErrXit("runTLB: 'loads(%x(array), %ld(range), %ld(stride), %ld(MHz), 0(fp), 0(delay))` returned elapsed time of 0us",
  328. array, range, stride, MHz);
  329. #ifdef EPSILON1
  330. } while ((((fabs(time - last) / (dbl)time) > EPSILON1) || (stride < (pgsz / 1))) && (range <= (maxrange / 2)));
  331. /* } while (((fabs(time - last) / (dbl)time) > EPSILON1) && (range <= (maxrange / 2))); */
  332. #endif
  333. #ifdef EPSILON3
  334. } while ((fabs(CYperIt(time) - CYperIt(last)) > EPSILON3) || (stride < (pgsz / 1))) && (range <= (maxrange / 2)));
  335. /* } while (fabs(CYperIt(time) - CYperIt(last)) > EPSILON3) && (range <= (maxrange / 2))); */
  336. #endif
  337. *maxstride = s;
  338. delay = 0;
  339. } else {
  340. delay = 1;
  341. }
  342. minspots = MAX(MINRANGE / (minstride + shift), 4);
  343. maxspots = maxrange / (*maxstride + shift);
  344. /* maxspots = mincachelines; */
  345. for (p = minspots, y = 2; p <= maxspots; p *= 2) {
  346. for (i = 3; i <= 5; i++) {
  347. spots = p * f * i;
  348. if ((spots * (*maxstride + shift)) <= maxrange) {
  349. for (s = *maxstride, x = 2; s >= minstride; s /= 2, x++) {
  350. }
  351. y++;
  352. }
  353. }
  354. }
  355. if (!(result = (lng**)malloc(y * sizeof(lng*))))
  356. ErrXit("runTLB: 'result = malloc(%ld)` failed", y * sizeof(lng*));
  357. for (z = 0; z < y; z++) {
  358. if (!(result[z] = (lng*)malloc(x * sizeof(lng))))
  359. ErrXit("runTLB: 'result[%ld] = malloc(%ld)` failed", z, x * sizeof(lng*));
  360. memset(result[z], 0, x * sizeof(lng));
  361. }
  362. result[0][0] = (y << 24) | x;
  363. fprintf(fp, "# Calibrator v%s\n", VERSION);
  364. fprintf(fp, "# (by Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/)\n");
  365. for (p = minspots, y = 2; p <= maxspots; p *= 2) {
  366. for (i = 3; i <= 5; i++) {
  367. spots = p * f * i;
  368. if ((spots * (*maxstride + shift)) <= maxrange) {
  369. result[y][0] = spots;
  370. fprintf(fp, "%09ld %08.1f"
  371. ,spots /* # spots accessed */
  372. ,((float)NUMLOADS) / ((float)spots) /* # accesses per spot */
  373. );
  374. fflush(fp);
  375. tmax = 0;
  376. smin = *maxstride + shift;
  377. xmin = 2;
  378. for (s = *maxstride, x = 2; s >= minstride; s /= 2, x++) {
  379. stride = s + shift;
  380. if (!result[0][x]) {
  381. result[0][x] = stride;
  382. }
  383. range = stride * spots;
  384. fprintf(fp, " %06ld %08.1f %05ld"
  385. ,stride /* stride */
  386. ,range / 1024.0 /* range in KB */
  387. ,range / pgsz /* # pages covered */
  388. );
  389. fflush(fp);
  390. result[y][x] = loads(array, range, stride, MHz, fp, delay);
  391. if (result[y][x] > tmax) {
  392. tmax = result[y][x];
  393. if (stride < smin) {
  394. smin = stride;
  395. xmin = x;
  396. }
  397. }
  398. }
  399. result[y][1] = tmax;
  400. result[1][xmin]++;
  401. fprintf(fp, "\n");
  402. fflush(fp);
  403. y++;
  404. }
  405. }
  406. }
  407. xmin = --x;
  408. for (--x; x >= 2; x--) {
  409. if (result[1][x] > result[1][xmin]) {
  410. xmin = x;
  411. }
  412. }
  413. result[0][1] = result[0][xmin];
  414. fprintf(stderr, "\n\n");
  415. fflush(stderr);
  416. return result;
  417. }
  418. typedef struct {
  419. lng levels;
  420. lng size[MAXLEVELS];
  421. lng linesize[MAXLEVELS];
  422. lng latency1[MAXLEVELS];
  423. lng latency2[MAXLEVELS];
  424. } cacheInfo;
  425. cacheInfo* analyzeCache(lng **result1, lng **result2, lng MHz)
  426. {
  427. lng x, y, xx, yy, range, lastrange, stride, level, a, l, n;
  428. lng last[LENPLATEAU], time1, time2, lasttime1, lasttime2;
  429. lng diff;
  430. cacheInfo *draft, *cache;
  431. if (!(draft = (cacheInfo*)malloc(4 * sizeof(cacheInfo))))
  432. ErrXit("analyzeCache: 'draft = malloc(%ld)` failed", 4 * sizeof(cacheInfo));
  433. if (!(cache = (cacheInfo*)malloc(sizeof(cacheInfo))))
  434. ErrXit("analyzeCache: 'cache = malloc(%ld)` failed", sizeof(cacheInfo));
  435. memset(draft, 0, 4 * sizeof(cacheInfo));
  436. memset(cache, 0, sizeof(cacheInfo));
  437. xx = (result1[0][0] & 0xffffff) - 1;
  438. yy = (result1[0][0] >> 24) - 1;
  439. level = 0;
  440. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  441. a = LENPLATEAU;
  442. lastrange = 0;
  443. lasttime1 = 0;
  444. lasttime2 = 0;
  445. for (y = 1; y <= yy ; y++) {
  446. range = result1[y][0];
  447. for (x = 1; x <= xx; x++) {
  448. stride = result1[0][x];
  449. time1 = result1[y][x];
  450. time2 = result2[y][x];
  451. if (draft[1].linesize[level] && last[a] && (range == draft[1].size[level])) {
  452. #ifdef EPSILON1
  453. if ((fabs(time1 - last[a]) / (dbl)time1) < EPSILON1) {
  454. #endif
  455. #ifdef EPSILON3
  456. if (fabs(CYperIt(time1) - CYperIt(last[a])) < EPSILON3) {
  457. #endif
  458. draft[0].linesize[level] = stride;
  459. draft[1].linesize[level] = stride;
  460. }
  461. }
  462. if (draft[2].linesize[level] && last[0] && lastrange && (lastrange == draft[2].size[level])) {
  463. #ifdef EPSILON1
  464. if ((fabs(time1 - last[0]) / (dbl)time1) < EPSILON1) {
  465. #endif
  466. #ifdef EPSILON3
  467. if (fabs(CYperIt(time1) - CYperIt(last[0])) < EPSILON3) {
  468. #endif
  469. draft[2].linesize[level] = stride;
  470. draft[3].linesize[level] = stride;
  471. if (x == xx) {
  472. level++;
  473. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  474. a = LENPLATEAU;
  475. }
  476. } else {
  477. level++;
  478. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  479. a = LENPLATEAU;
  480. }
  481. }
  482. #ifdef EPSILON2
  483. if ((x == 1) && (!draft[2].linesize[level]) && ((last[0] && ((FABS(time1 - last[LENPLATEAU - 1]) / (dbl)last[LENPLATEAU - 1]) > EPSILON2)) || (y == yy))) {
  484. #endif
  485. #ifdef EPSILON4
  486. if ((x == 1) && (!draft[2].linesize[level]) && ((last[0] && (FABS(CYperIt(time1) - CYperIt(last[LENPLATEAU - 1])) >= EPSILON4)) || (y == yy))) {
  487. #endif
  488. draft[2].linesize[level] = draft[1].linesize[level];
  489. draft[2].size[level] = lastrange;
  490. draft[2].latency1[level] = lasttime1;
  491. draft[2].latency2[level] = lasttime2;
  492. draft[3].linesize[level] = stride;
  493. draft[3].size[level] = range;
  494. draft[3].latency1[level] = time1;
  495. draft[3].latency2[level] = time2;
  496. last[0] = time1;
  497. }
  498. if ((x == 1) && (a < LENPLATEAU) && (!last[0])) {
  499. #ifdef EPSILON2
  500. if ((FABS(time1 - last[LENPLATEAU - 1]) / (dbl)last[LENPLATEAU - 1]) < EPSILON2) {
  501. #endif
  502. #ifdef EPSILON4
  503. if (FABS(CYperIt(time1) - CYperIt(last[LENPLATEAU - 1])) <= EPSILON4) {
  504. #endif
  505. last[--a] = time1;
  506. } else {
  507. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  508. a = LENPLATEAU;
  509. }
  510. }
  511. if ((x == 1) && (a == LENPLATEAU)) {
  512. last[--a] = time1;
  513. draft[0].linesize[level] = stride;
  514. draft[0].size[level] = lastrange;
  515. draft[0].latency1[level] = lasttime1;
  516. draft[0].latency2[level] = lasttime2;
  517. draft[1].linesize[level] = stride;
  518. draft[1].size[level] = range;
  519. draft[1].latency1[level] = time1;
  520. draft[1].latency2[level] = time2;
  521. }
  522. if (x == 1) {
  523. lasttime1 = time1;
  524. lasttime2 = time2;
  525. }
  526. }
  527. lastrange = range;
  528. }
  529. #ifdef DEBUG
  530. {
  531. lng ll;
  532. for (l = 0; l < level; l++) {
  533. for (ll = 0; ll < 4; ll++) {
  534. fprintf(stderr, "%2ld %5ld %3ld %05.1f %05.1f\n",
  535. l, draft[ll].size[l] / 1024, draft[ll].linesize[l], NSperIt(draft[ll].latency1[l]), CYperIt(draft[ll].latency1[l]));
  536. }
  537. fprintf(stderr, "\n");
  538. }
  539. fflush(stderr);
  540. }
  541. #endif
  542. for (l = n = 0 ; n < level; n++) {
  543. cache->latency1[l] = ((dbl)(draft[2].latency1[n] + draft[1].latency1[n]) / 2.0);
  544. cache->latency2[l] = ((dbl)(draft[2].latency2[n] + draft[1].latency2[n]) / 2.0);
  545. if ((l == 0) || ((log10(cache->latency1[l]) - log10(cache->latency1[l - 1])) > 0.3)) {
  546. cache->linesize[l] = draft[1].linesize[n];
  547. diff = -1;
  548. for (range = 1; range < result1[1][0]; range *= 2);
  549. for (y = 1; result1[y][0] < range; y++);
  550. if (l) {
  551. int yyy = 1;
  552. for (; y <= yy; y += yyy) {
  553. range = result1[y][0];
  554. if ((draft[2].size[n - 1] <= range) && (range < draft[1].size[n])) {
  555. if ((y > yyy) && (((result1[y][1]) - (result1[y - yyy][1])) > diff)) {
  556. diff = (result1[y][1]) - (result1[y - yyy][1]);
  557. cache->size[l - 1] = range;
  558. }
  559. if (((y + yyy) <= yy) && (((result1[y + yyy][1]) - (result1[y][1])) > diff)) {
  560. diff = (result1[y + yyy][1]) - (result1[y][1]);
  561. cache->size[l - 1] = range;
  562. }
  563. }
  564. }
  565. }
  566. l++;
  567. }
  568. }
  569. cache->size[--l] = draft[3].size[--n];
  570. cache->levels = l;
  571. #ifdef DEBUG
  572. for (l = 0; l <= cache->levels; l++) {
  573. fprintf(stderr, "%2ld %5ld %3ld %05.1f %05.1f\n",
  574. l, cache->size[l] / 1024, cache->linesize[l], NSperIt(cache->latency1[l]), CYperIt(cache->latency1[l]));
  575. }
  576. fprintf(stderr, "\n");
  577. fflush(stderr);
  578. #endif
  579. free(draft);
  580. draft = 0;
  581. return cache;
  582. }
  583. typedef struct {
  584. lng levels;
  585. lng shift;
  586. lng mincachelines;
  587. lng entries[MAXLEVELS];
  588. lng pagesize[MAXLEVELS];
  589. lng latency1[MAXLEVELS];
  590. lng latency2[MAXLEVELS];
  591. } TLBinfo;
  592. TLBinfo* analyzeTLB(lng **result1, lng **result2, lng shift, lng mincachelines, lng MHz)
  593. {
  594. lng x, y, xx, yy, spots, lastspots, stride, level, a, l, limit = 0, n;
  595. lng last[LENPLATEAU], time1, time2, lasttime1, lasttime2;
  596. dbl diff;
  597. TLBinfo *draft, *TLB;
  598. if (!(draft = (TLBinfo*)malloc(4 * sizeof(TLBinfo))))
  599. ErrXit("analyzeCache: 'draft = malloc(%ld)` failed", 4 * sizeof(TLBinfo));
  600. if (!(TLB = (TLBinfo*)malloc(sizeof(TLBinfo))))
  601. ErrXit("analyzeCache: 'TLB = malloc(%ld)` failed", sizeof(TLBinfo));
  602. memset(draft, 0, 4 * sizeof(TLBinfo));
  603. memset(TLB, 0, sizeof(TLBinfo));
  604. TLB->shift = shift;
  605. TLB->mincachelines = mincachelines;
  606. xx = (result1[0][0] & 0xffffff) - 1;
  607. yy = (result1[0][0] >> 24) - 1;
  608. level = 0;
  609. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  610. a = LENPLATEAU;
  611. lastspots = 0;
  612. lasttime1 = 0;
  613. lasttime2 = 0;
  614. for (y = 2; !limit; y++) {
  615. spots = result1[y][0];
  616. limit = (y >= yy) || (spots >= (TLB->mincachelines * 1.25));
  617. for (x = 1; x <= xx; x++) {
  618. stride = result1[0][x];
  619. time1 = result1[y][x];
  620. time2 = result2[y][x];
  621. if (draft[1].pagesize[level] && last[a] && (spots == draft[1].entries[level])) {
  622. #ifdef EPSILON1
  623. if (((fabs(time1 - last[a]) / (dbl)time1) < EPSILON1) || (stride >= result1[0][1])) {
  624. #endif
  625. #ifdef EPSILON3
  626. if ((fabs(CYperIt(time1) - CYperIt(last[a])) < EPSILON3) || (stride >= result1[0][1])) {
  627. #endif
  628. draft[0].pagesize[level] = stride;
  629. draft[1].pagesize[level] = stride;
  630. }
  631. }
  632. if (draft[2].pagesize[level] && last[0] && lastspots && (lastspots == draft[2].entries[level])) {
  633. #ifdef EPSILON1
  634. if (((fabs(time1 - last[0]) / (dbl)time1) < EPSILON1) || (stride >= result1[0][1])) {
  635. #endif
  636. #ifdef EPSILON3
  637. if ((fabs(CYperIt(time1) - CYperIt(last[0])) < EPSILON3) || (stride >= result1[0][1])) {
  638. #endif
  639. draft[2].pagesize[level] = stride;
  640. draft[3].pagesize[level] = stride;
  641. if (x == xx) {
  642. level++;
  643. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  644. a = LENPLATEAU;
  645. }
  646. } else {
  647. level++;
  648. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  649. a = LENPLATEAU;
  650. }
  651. }
  652. #ifdef EPSILON2
  653. if ((x == 1) && (!draft[2].pagesize[level]) && ((last[0] && ((FABS(time1 - last[LENPLATEAU - 1]) / (dbl)last[LENPLATEAU - 1]) > EPSILON2)) || limit)) {
  654. #endif
  655. #ifdef EPSILON4
  656. if ((x == 1) && (!draft[2].pagesize[level]) && ((last[0] && (FABS(CYperIt(time1) - CYperIt(last[LENPLATEAU - 1])) >= EPSILON4)) || limit)) {
  657. #endif
  658. draft[2].pagesize[level] = draft[1].pagesize[level];
  659. draft[2].entries[level] = lastspots;
  660. draft[2].latency1[level] = lasttime1;
  661. draft[2].latency2[level] = lasttime2;
  662. draft[3].pagesize[level] = stride;
  663. draft[3].entries[level] = spots;
  664. draft[3].latency1[level] = time1;
  665. draft[3].latency2[level] = time2;
  666. last[0] = time1;
  667. }
  668. if ((x == 1) && (a < LENPLATEAU) && (!last[0])) {
  669. #ifdef EPSILON2
  670. if ((FABS(time1 - last[LENPLATEAU - 1]) / (dbl)last[LENPLATEAU - 1]) < EPSILON2) {
  671. #endif
  672. #ifdef EPSILON4
  673. if (FABS(CYperIt(time1) - CYperIt(last[LENPLATEAU - 1])) <= EPSILON4) {
  674. #endif
  675. last[--a] = time1;
  676. } else {
  677. memset(last, 0, LENPLATEAU * sizeof(last[0]));
  678. a = LENPLATEAU;
  679. }
  680. }
  681. if ((x == 1) && (a == LENPLATEAU)) {
  682. last[--a] = time1;
  683. draft[0].pagesize[level] = stride;
  684. draft[0].entries[level] = lastspots;
  685. draft[0].latency1[level] = lasttime1;
  686. draft[0].latency2[level] = lasttime2;
  687. draft[1].pagesize[level] = stride;
  688. draft[1].entries[level] = spots;
  689. draft[1].latency1[level] = time1;
  690. draft[1].latency2[level] = time2;
  691. }
  692. if (x == 1) {
  693. lasttime1 = time1;
  694. lasttime2 = time2;
  695. }
  696. }
  697. lastspots = spots;
  698. }
  699. #ifdef DEBUG
  700. {
  701. lng ll;
  702. for (l = 0; l < level; l++) {
  703. for (ll = 0; ll < 4; ll++) {
  704. fprintf(stderr, "%2ld %5ld %5ld %05.1f %05.1f\n",
  705. l, draft[ll].entries[l], draft[ll].pagesize[l], NSperIt(draft[ll].latency1[l]), CYperIt(draft[ll].latency1[l]));
  706. }
  707. fprintf(stderr, "\n");
  708. }
  709. fflush(stderr);
  710. }
  711. #endif
  712. for (l = n = 0; n < level; n++) {
  713. TLB->latency1[l] = ((dbl)(draft[2].latency1[n] + draft[1].latency1[n]) / 2.0);
  714. TLB->latency2[l] = ((dbl)(draft[2].latency2[n] + draft[1].latency2[n]) / 2.0);
  715. if ((l == 0) || (((log10(TLB->latency1[l]) - log10(TLB->latency1[l - 1])) > 0.3) && (draft[2].entries[l] > draft[1].entries[l]))) {
  716. TLB->pagesize[l] = draft[1].pagesize[n];
  717. diff = -1.0;
  718. for (spots = 1; spots < result1[2][0]; spots *= 2);
  719. for (y = 2; result1[y][0] < spots; y++);
  720. if (l) {
  721. int yyy = 1;
  722. for (; y <= yy; y += yyy) {
  723. spots = result1[y][0];
  724. if ((draft[2].entries[n - 1] <= spots) && (spots < draft[1].entries[n])) {
  725. if ((y > 4) && ((log(result1[y][1]) - log(result1[y - yyy][1])) > diff)) {
  726. diff = log(result1[y][1]) - log(result1[y - yyy][1]);
  727. TLB->entries[l - 1] = spots;
  728. }
  729. if (((y + yyy) <= yy) && ((log(result1[y + yyy][1]) - log(result1[y][1])) > diff)) {
  730. diff = log(result1[y + yyy][1]) - log(result1[y][1]);
  731. TLB->entries[l - 1] = spots;
  732. }
  733. }
  734. }
  735. }
  736. l++;
  737. }
  738. }
  739. TLB->entries[--l] = draft[3].entries[--n];
  740. TLB->levels = l;
  741. #ifdef DEBUG
  742. for (l = 0; l <= TLB->levels; l++) {
  743. fprintf(stderr, "%2ld %5ld %5ld %05.1f %05.1f\n",
  744. l, TLB->entries[l], TLB->pagesize[l], NSperIt(TLB->latency1[l]), CYperIt(TLB->latency1[l]));
  745. }
  746. fprintf(stderr, "\n");
  747. fflush(stderr);
  748. #endif
  749. free(draft);
  750. draft = 0;
  751. return TLB;
  752. }
  753. void plotCache(cacheInfo *cache, lng **result, lng MHz, char *fn, FILE *fp, lng delay)
  754. {
  755. lng l, x, xx = (result[0][0] & 0xffffff) - 1, y, yy = (result[0][0] >> 24) - 1;
  756. dbl xl, xh, yl, yh, z;
  757. char *s;
  758. xl = (dbl)result[1][0] / 1024.0;
  759. xh = (dbl)result[yy][0] / 1024.0;
  760. yl = 1.0;
  761. for (yh = 1000; yh < (lng)NSperIt(result[yy][1] - delay); yh *= 10);
  762. fprintf(fp, "# Calibrator v%s\n", VERSION);
  763. fprintf(fp, "# (by Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/)\n");
  764. fprintf(fp, " set term postscript portrait enhanced\n");
  765. fprintf(fp, " set output '%s.ps'\n", fn);
  766. fprintf(fp, "#set term gif transparent interlace small size 500, 707 # xFFFFFF x333333 x333333 x0055FF x005522 x660000 xFF0000 x00FF00 x0000FF\n");
  767. fprintf(fp, "#set output '%s.gif'\n", fn);
  768. fprintf(fp, "set data style linespoints\n");
  769. fprintf(fp, "set key below\n");
  770. fprintf(fp, "set title '%s'\n", fn);
  771. fprintf(fp, "set xlabel 'memory range [bytes]'\n");
  772. fprintf(fp, "set x2label ''\n");
  773. fprintf(fp, "set ylabel 'nanosecs per iteration'\n");
  774. fprintf(fp, "set y2label 'cycles per iteration'\n");
  775. fprintf(fp, "set logscale x 2\n");
  776. fprintf(fp, "set logscale x2 2\n");
  777. fprintf(fp, "set logscale y 10\n");
  778. fprintf(fp, "set logscale y2 10\n");
  779. fprintf(fp, "set format x '%%1.0f'\n");
  780. fprintf(fp, "set format x2 '%%1.0f'\n");
  781. fprintf(fp, "set format y '%%1.0f'\n");
  782. fprintf(fp, "set format y2 ''\n");
  783. fprintf(fp, "set xrange[%f:%f]\n", xl, xh);
  784. fprintf(fp, "#set x2range[%f:%f]\n", xl, xh);
  785. fprintf(fp, "set yrange[%f:%f]\n", yl, yh);
  786. fprintf(fp, "#set y2range[%f:%f]\n", yl, yh);
  787. fprintf(fp, "set grid x2tics\n");
  788. fprintf(fp, "set xtics mirror");
  789. for (x = 1, l = 1, s = " ("; x <= xh; x *= 2, l++, s = ", ") {
  790. if (l&1) {
  791. if (x >= (1024 * 1024)) {
  792. fprintf(fp, "%s'%ldG' %ld", s, x / (1024 * 1024), x);
  793. } else if (x >= 1024) {
  794. fprintf(fp, "%s'%ldM' %ld", s, x / 1024, x);
  795. } else {
  796. fprintf(fp, "%s'%ldk' %ld", s, x, x);
  797. }
  798. } else {
  799. fprintf(fp, "%s'' %ld", s, x);
  800. }
  801. }
  802. fprintf(fp, ")\n");
  803. fprintf(fp, "set x2tics mirror");
  804. for (l = 0, s = " ("; l < cache->levels; l++, s = ", ") {
  805. if (cache->size[l] >= (1024 * 1024 * 1024)) {
  806. fprintf(fp, "%s'[%ldG]' %ld", s, cache->size[l] / (1024 * 1024 * 1024), cache->size[l] / 1024);
  807. } else if (cache->size[l] >= (1024 * 1024)) {
  808. fprintf(fp, "%s'[%ldM]' %ld", s, cache->size[l] / (1024 * 1024), cache->size[l] / 1024);
  809. } else {
  810. fprintf(fp, "%s'[%ldk]' %ld", s, cache->size[l] / 1024, cache->size[l] / 1024);
  811. }
  812. }
  813. fprintf(fp, ")\n");
  814. fprintf(fp, "set y2tics");
  815. for (l = 0, s = " ("; l <= cache->levels; l++, s = ", ") {
  816. if (!delay) fprintf(fp, "%s'(%ld)' %f", s, round(CYperIt(cache->latency1[l] - delay)), NSperIt(cache->latency1[l] - delay));
  817. else fprintf(fp, "%s'(%ld)' %f", s, round(CYperIt(cache->latency2[l] - delay)), NSperIt(cache->latency2[l] - delay));
  818. }
  819. for (y = 1; y <= yh; y *= 10) {
  820. fprintf(fp, "%s'%1.3g' %ld", s, (dbl)(y * MHz) / 1000.0, y);
  821. }
  822. fprintf(fp, ")\n");
  823. for (l = 0; l <= cache->levels; l++) {
  824. if (!delay) z = (dbl)round(CYperIt(cache->latency1[l] - delay)) * 1000.0 / (dbl)MHz;
  825. else z = (dbl)round(CYperIt(cache->latency2[l] - delay)) * 1000.0 / (dbl)MHz;
  826. fprintf(fp, "set label %ld '(%1.3g) ' at %f,%f right\n", l + 1, z, xl, z);
  827. fprintf(fp, "set arrow %ld from %f,%f to %f,%f nohead lt 0\n", l + 1, xl, z, xh, z);
  828. }
  829. fprintf(fp, " set label %ld '^{ Calibrator v%s (Stefan.Manegold\\@cwi.nl, www.cwi.nl/~manegold) }' at graph 0.5,graph 0.02 center\n", l + 1, VERSION);
  830. fprintf(fp, "#set label %ld 'Calibrator v%s (Stefan.Manegold@cwi.nl, www.cwi.nl/~manegold)' at graph 0.5,graph 0.03 center\n", l + 1, VERSION);
  831. fprintf(fp, "plot \\\n0.1 title 'stride:' with points pt 0 ps 0");
  832. for (x = 1, l = cache->levels; x <= xx; x++) {
  833. fprintf(fp, " , \\\n'%s.data' using 1:($%ld-%f) title '", fn, (6 * x) + 1, NSperIt(delay));
  834. if ((l > 0) && (result[0][x] == cache->linesize[l])) {
  835. fprintf(fp, "\\{%ld\\}", result[0][x]);
  836. while ((--l >= 0) && (result[0][x] == cache->linesize[l]));
  837. } else {
  838. fprintf(fp, "%ld", result[0][x]);
  839. }
  840. fprintf(fp, "' with linespoints lt %ld pt %ld", x, x + 2);
  841. }
  842. fprintf(fp, "\n");
  843. fprintf(fp, "set nolabel\n");
  844. fprintf(fp, "set noarrow\n");
  845. fflush(fp);
  846. }
  847. void plotTLB(TLBinfo *TLB, lng **result, lng MHz, char *fn, FILE *fp, lng delay)
  848. {
  849. lng l, x, xx = (result[0][0] & 0xffffff) - 1, y, yy = (result[0][0] >> 24) - 1;
  850. dbl xl, xh, yl, yh, z;
  851. char *s;
  852. xl = (dbl)result[2][0];
  853. xh = (dbl)result[yy][0];
  854. yl = 1.0;
  855. for (yh = 1000; yh < (lng)NSperIt(result[yy][2] - delay); yh *= 10);
  856. fprintf(fp, "# Calibrator v%s\n", VERSION);
  857. fprintf(fp, "# (by Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/)\n");
  858. fprintf(fp, " set term postscript portrait enhanced\n");
  859. fprintf(fp, " set output '%s.ps'\n", fn);
  860. fprintf(fp, "#set term gif transparent interlace small size 500, 707 # xFFFFFF x333333 x333333 x0055FF x005522 x660000 xFF0000 x00FF00 x0000FF\n");
  861. fprintf(fp, "#set output '%s.gif'\n", fn);
  862. fprintf(fp, "set data style linespoints\n");
  863. fprintf(fp, "set key below\n");
  864. fprintf(fp, "set title '%s'\n", fn);
  865. fprintf(fp, "set xlabel 'spots accessed'\n");
  866. fprintf(fp, "set x2label ''\n");
  867. fprintf(fp, "set ylabel 'nanosecs per iteration'\n");
  868. fprintf(fp, "set y2label 'cycles per iteration'\n");
  869. fprintf(fp, "set logscale x 2\n");
  870. fprintf(fp, "set logscale x2 2\n");
  871. fprintf(fp, "set logscale y 10\n");
  872. fprintf(fp, "set logscale y2 10\n");
  873. fprintf(fp, "set format x '%%1.0f'\n");
  874. fprintf(fp, "set format x2 '%%1.0f'\n");
  875. fprintf(fp, "set format y '%%1.0f'\n");
  876. fprintf(fp, "set format y2 ''\n");
  877. fprintf(fp, "set xrange[%f:%f]\n", xl, xh);
  878. fprintf(fp, "#set x2range[%f:%f]\n", xl, xh);
  879. fprintf(fp, "set yrange[%f:%f]\n", yl, yh);
  880. fprintf(fp, "#set y2range[%f:%f]\n", yl, yh);
  881. fprintf(fp, "set grid x2tics\n");
  882. fprintf(fp, "set xtics mirror");
  883. for (x = 1, l = 1, s = " ("; x <= xh; x *= 2, l++, s = ", ") {
  884. if (l | 1) {
  885. if (x >= (1024 * 1024)) {
  886. fprintf(fp, "%s'%ldM' %ld", s, x / (1024 * 1024), x);
  887. } else if (x >= 1024) {
  888. fprintf(fp, "%s'%ldk' %ld", s, x / 1024, x);
  889. } else {
  890. fprintf(fp, "%s'%ld' %ld", s, x, x);
  891. }
  892. } else {
  893. fprintf(fp, "%s'' %ld", s, x);
  894. }
  895. }
  896. fprintf(fp, ")\n");
  897. fprintf(fp, "set x2tics mirror");
  898. for (l = 0, s = " ("; l < TLB->levels; l++, s = ", ") {
  899. if (TLB->entries[l] >= (1024 * 1024)) {
  900. fprintf(fp, "%s'[%ldM]' %ld", s, TLB->entries[l] / (1024 * 1024), TLB->entries[l]);
  901. } else if (TLB->entries[l] >= 1024) {
  902. fprintf(fp, "%s'[%ldk]' %ld", s, TLB->entries[l] / 1024, TLB->entries[l]);
  903. } else {
  904. fprintf(fp, "%s'[%ld]' %ld", s, TLB->entries[l], TLB->entries[l]);
  905. }
  906. }
  907. fprintf(fp, "%s'<L1>' %ld)\n", s, TLB->mincachelines);
  908. fprintf(fp, "set y2tics");
  909. for (l = 0, s = " ("; l <= TLB->levels; l++, s = ", ") {
  910. if (!delay) fprintf(fp, "%s'(%ld)' %f", s, round(CYperIt(TLB->latency1[l] - delay)), NSperIt(TLB->latency1[l] - delay));
  911. else fprintf(fp, "%s'(%ld)' %f", s, round(CYperIt(TLB->latency2[l] - delay)), NSperIt(TLB->latency2[l] - delay));
  912. }
  913. for (y = 1; y <= yh; y *= 10) {
  914. fprintf(fp, "%s'%1.3g' %ld", s, (dbl)(y * MHz) / 1000.0, y);
  915. }
  916. fprintf(fp, ")\n");
  917. for (l = 0; l <= TLB->levels; l++) {
  918. if (!delay) z = (dbl)round(CYperIt(TLB->latency1[l] - delay)) * 1000.0 / (dbl)MHz;
  919. else z = (dbl)round(CYperIt(TLB->latency2[l] - delay)) * 1000.0 / (dbl)MHz;
  920. fprintf(fp, "set label %ld '(%1.3g) ' at %f,%f right\n", l + 1, z, xl, z);
  921. fprintf(fp, "set arrow %ld from %f,%f to %f,%f nohead lt 0\n", l + 1, xl, z, xh, z);
  922. }
  923. fprintf(fp, " set label %ld '^{ Calibrator v%s (Stefan.Manegold\\@cwi.nl, www.cwi.nl/~manegold) }' at graph 0.5,graph 0.02 center\n", l + 1, VERSION);
  924. fprintf(fp, "#set label %ld 'Calibrator v%s (Stefan.Manegold@cwi.nl, www.cwi.nl/~manegold)' at graph 0.5,graph 0.03 center\n", l + 1, VERSION);
  925. fprintf(fp, "plot \\\n0.1 title 'stride:' with points pt 0 ps 0");
  926. for (x = 2, l = TLB->levels; x <= xx; x++) {
  927. fprintf(fp, " , \\\n'%s.data' using 1:($%ld-%f) title '", fn, (6 * (x - 1)) + 1, NSperIt(delay));
  928. if ((l > 0) && (result[0][x] == TLB->pagesize[l])) {
  929. fprintf(fp, "\\{%ld\\}", result[0][x]);
  930. while ((--l >= 0) && (result[0][x] == TLB->pagesize[l]));
  931. } else {
  932. fprintf(fp, "%ld", result[0][x]);
  933. }
  934. fprintf(fp, "' with linespoints lt %ld pt %ld", x, x + 2);
  935. }
  936. fprintf(fp, "\n");
  937. fprintf(fp, "set nolabel\n");
  938. fprintf(fp, "set noarrow\n");
  939. fflush(fp);
  940. }
  941. void printCPU(cacheInfo *cache, lng MHz, lng delay)
  942. {
  943. FILE *fp = stdout;
  944. fprintf(fp, "CPU loop + L1 access: ");
  945. fprintf(fp, " %6.2f ns = %3ld cy\n", NSperIt(cache->latency1[0]), round(CYperIt(cache->latency1[0])));
  946. fprintf(fp, " ( delay: ");
  947. fprintf(fp, " %6.2f ns = %3ld cy )\n", NSperIt(delay), round(CYperIt(delay)));
  948. fprintf(fp, "\n");
  949. fflush(fp);
  950. }
  951. void printCache(cacheInfo *cache, lng MHz)
  952. {
  953. lng l;
  954. FILE *fp = stdout;
  955. fprintf(fp, "caches:\n");
  956. fprintf(fp, "level size linesize miss-latency replace-time\n");
  957. for (l = 0; l < cache->levels; l++) {
  958. fprintf(fp, " %1ld ", l+1);
  959. if (cache->size[l] >= (1024 * 1024 * 1024)) {
  960. fprintf(fp, " %3ld GB ", cache->size[l] / (1024 * 1024 * 1024));
  961. } else if (cache->size[l] >= (1024 * 1024)) {
  962. fprintf(fp, " %3ld MB ", cache->size[l] / (1024 * 1024));
  963. } else {
  964. fprintf(fp, " %3ld KB ", cache->size[l] / 1024);
  965. }
  966. fprintf(fp, " %3ld bytes ", cache->linesize[l + 1]);
  967. fprintf(fp, " %6.2f ns = %3ld cy " , NSperIt(cache->latency2[l + 1] - cache->latency2[l]), round(CYperIt(cache->latency2[l + 1] - cache->latency2[l])));
  968. fprintf(fp, " %6.2f ns = %3ld cy\n", NSperIt(cache->latency1[l + 1] - cache->latency1[l]), round(CYperIt(cache->latency1[l + 1] - cache->latency1[l])));
  969. }
  970. fprintf(fp, "\n");
  971. fflush(fp);
  972. }
  973. void printTLB(TLBinfo *TLB, lng MHz)
  974. {
  975. lng l;
  976. FILE *fp = stdout;
  977. fprintf(fp, "TLBs:\n");
  978. fprintf(fp, "level #entries pagesize miss-latency");
  979. /*
  980. fprintf(fp, " replace-time");
  981. */
  982. fprintf(fp, "\n");
  983. for (l = 0; l < TLB->levels; l++) {
  984. fprintf(fp, " %1ld ", l+1);
  985. fprintf(fp, " %3ld ", TLB->entries[l]);
  986. if (TLB->pagesize[l + 1] >= (1024 * 1024 * 1024)) {
  987. fprintf(fp, " %3ld GB ", TLB->pagesize[l + 1] / (1024 * 1024 * 1024));
  988. } else if (TLB->pagesize[l + 1] >= (1024 * 1024)) {
  989. fprintf(fp, " %3ld MB ", TLB->pagesize[l + 1] / (1024 * 1024));
  990. } else {
  991. fprintf(fp, " %3ld KB ", TLB->pagesize[l + 1] / 1024);
  992. }
  993. fprintf(fp, " %6.2f ns = %3ld cy ", NSperIt(TLB->latency2[l + 1] - TLB->latency2[l]), round(CYperIt(TLB->latency2[l + 1] - TLB->latency2[l])));
  994. /*
  995. fprintf(fp, " %6.2f ns = %3ld cy" , NSperIt(TLB->latency1[l + 1] - TLB->latency1[l]), round(CYperIt(TLB->latency1[l + 1] - TLB->latency1[l])));
  996. */
  997. fprintf(fp, "\n");
  998. }
  999. fprintf(fp, "\n");
  1000. fflush(fp);
  1001. }
  1002. lng getMINTIME () {
  1003. lng t0=0, t1=0;
  1004. t0=t1=now();
  1005. while(t0==t1){
  1006. t1=now();
  1007. }
  1008. return (t1-t0);
  1009. }
  1010. int main(int ac, char **av)
  1011. {
  1012. lng MHz, maxrange, mincachelines, maxlinesize, minstride = (lng)sizeof(char*), yy, y;
  1013. lng maxCstride=0, maxTstride=0, delayC, delayT;
  1014. char *array0, *array, fnn1[1024], fnx1[1024], fnn2[1024], fnx2[1024];
  1015. FILE *fp;
  1016. lng **result1, **result2;
  1017. cacheInfo *cache;
  1018. TLBinfo *TLB;
  1019. lng align = 0, pgsz = getpagesize();
  1020. fprintf(stdout,"\nCalibrator v%s\n(by Stefan.Manegold@cwi.nl, http://www.cwi.nl/~manegold/)\n", VERSION);
  1021. if (ac < 4) ErrXit("usage: '%s <MHz> <size>[k|M|G] <filename>`", av[0]);
  1022. MHz = atoi(av[1]);
  1023. maxrange = bytes(av[2]) * 1.25;
  1024. if (ac > 4) align = atoi(av[4]) % pgsz;
  1025. if (ac > 5) maxCstride = -1 * abs(atoi(av[5]));
  1026. if (!(array0 = (char *)malloc(maxrange+pgsz)))
  1027. ErrXit("main: 'array0 = malloc(%ld)` failed", maxrange+pgsz);
  1028. array = array0;
  1029. fprintf(stderr,"%x %ld %ld %5ld\n",array,(lng)array,pgsz,(lng)array%pgsz);
  1030. while (((lng)array % pgsz) != align) {
  1031. fprintf(stderr,"\r%x %ld %ld %5ld",array,(lng)array,pgsz,(lng)array%pgsz);
  1032. fflush(stderr);
  1033. array++;
  1034. }
  1035. fprintf(stderr,"\n%x %ld %ld %5ld\n\n",array,(lng)array,pgsz,(lng)array%pgsz);
  1036. fflush(stderr);
  1037. MINTIME = MAX( MINTIME, 10*getMINTIME() );
  1038. fprintf(stderr,"MINTIME = %ld\n\n",MINTIME);
  1039. fflush(stderr);
  1040. sprintf(fnn1, "%s.cache-replace-time", av[3]);
  1041. sprintf(fnx1, "%s.data", fnn1);
  1042. if (!(fp = fopen(fnx1,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx1);
  1043. result1 = runCache(array, maxrange, minstride, MHz, fp, &maxCstride);
  1044. fclose(fp);
  1045. sprintf(fnn2, "%s.cache-miss-latency", av[3]);
  1046. sprintf(fnx2, "%s.data", fnn2);
  1047. if (!(fp = fopen(fnx2,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx2);
  1048. result2 = runCache(array, maxrange, minstride, MHz, fp, &maxCstride);
  1049. fclose(fp);
  1050. cache = analyzeCache(result1, result2, MHz);
  1051. mincachelines = ( cache->size[0] && cache->linesize[1] ? cache->size[0] / cache->linesize[1] : 1024 );
  1052. maxlinesize = ( cache->linesize[cache->levels] ? cache->linesize[cache->levels] : maxCstride / 2 );
  1053. delayC = cache->latency2[0] - cache->latency1[0];
  1054. sprintf(fnx1, "%s.gp", fnn1);
  1055. if (!(fp = fopen(fnx1,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx1);
  1056. plotCache(cache, result1, MHz, fnn1, fp, 0);
  1057. fclose(fp);
  1058. sprintf(fnx2, "%s.gp", fnn2);
  1059. if (!(fp = fopen(fnx2,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx2);
  1060. plotCache(cache, result2, MHz, fnn2, fp, delayC);
  1061. fclose(fp);
  1062. yy = (result1[0][0] >> 24) - 1;
  1063. for (y = 0; y <= yy; y++) {
  1064. free(result1[y]);
  1065. result1[y] = 0;
  1066. }
  1067. free(result1);
  1068. result1 = 0;
  1069. yy = (result2[0][0] >> 24) - 1;
  1070. for (y = 0; y <= yy; y++) {
  1071. free(result2[y]);
  1072. result2[y] = 0;
  1073. }
  1074. free(result2);
  1075. result2 = 0;
  1076. sprintf(fnn1, "%s.TLB-miss-latency", av[3]);
  1077. sprintf(fnx1, "%s.data", fnn1);
  1078. if (!(fp = fopen(fnx1,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx1);
  1079. result1 = runTLB(array, maxrange, 1024, maxlinesize, mincachelines, MHz, fp, &maxTstride);
  1080. fclose(fp);
  1081. /*
  1082. sprintf(fnn2, "%s.TLB2", av[3]);
  1083. sprintf(fnx2, "%s.data", fnn2);
  1084. if (!(fp = fopen(fnx2,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx2);
  1085. result2 = runTLB(array, maxrange, 1024, maxlinesize, mincachelines, MHz, fp, &maxTstride);
  1086. fclose(fp);
  1087. */
  1088. result2 = result1;
  1089. TLB = analyzeTLB(result1, result2, maxlinesize, mincachelines, MHz);
  1090. delayT = TLB->latency2[0] - TLB->latency1[0];
  1091. sprintf(fnx1, "%s.gp", fnn1);
  1092. if (!(fp = fopen(fnx1,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx1);
  1093. plotTLB(TLB, result1, MHz, fnn1, fp, 0);
  1094. fclose(fp);
  1095. /*
  1096. sprintf(fnx2, "%s.gp", fnn2);
  1097. if (!(fp = fopen(fnx2,"w"))) ErrXit("main: 'fp = fopen(%s,\"w\")` failed", fnx2);
  1098. plotTLB(TLB, result2, MHz, fnn2, fp, delayT);
  1099. fclose(fp);
  1100. */
  1101. yy = (result1[0][0] >> 24) - 1;
  1102. for (y = 0; y <= yy; y++) {
  1103. free(result1[y]);
  1104. result1[y] = 0;
  1105. }
  1106. free(result1);
  1107. result1 = 0;
  1108. /*
  1109. yy = (result2[0][0] >> 24) - 1;
  1110. for (y = 0; y <= yy; y++) {
  1111. free(result2[y]);
  1112. result2[y] = 0;
  1113. }
  1114. free(result2);
  1115. */
  1116. result2 = 0;
  1117. fprintf(stdout,"\n");
  1118. printCPU(cache, MHz, delayC);
  1119. printCache(cache, MHz);
  1120. printTLB(TLB, MHz);
  1121. free(cache);
  1122. cache = 0;
  1123. free(TLB);
  1124. TLB = 0;
  1125. return(0);
  1126. }