PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/papi-4.4.0/src/papi_libpfm_presets.c

#
C | 577 lines | 468 code | 63 blank | 46 comment | 157 complexity | 6b9d402e8d502004da71be628aa10f3d MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * File: papi_libpfm_presets.c
  3. * Author: Vince Weaver vweaver1 @ eecs.utk.edu
  4. * Merge of the libpfm3/libpfm4/pmapi-ppc64_events preset code
  5. */
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include <errno.h>
  9. #include "papi.h"
  10. #include "papi_internal.h"
  11. #include "papi_setup_presets.h"
  12. #define PAPI_EVENT_FILE "papi_events.csv"
  13. typedef struct
  14. {
  15. int preset; /* Preset code */
  16. int derived; /* Derived code */
  17. char *( findme[PAPI_MAX_COUNTER_TERMS] ); /* Strings to look for, more than 1 means derived */
  18. char *operation; /* PostFix operations between terms */
  19. char *note; /* In case a note is included with a preset */
  20. } pfm_preset_search_entry_t;
  21. /* Trims blank space from both ends of a string (in place).
  22. Returns pointer to new start address */
  23. static inline char *
  24. trim_string( char *in )
  25. {
  26. int len, i = 0;
  27. char *start = in;
  28. if ( in == NULL )
  29. return ( in );
  30. len = ( int ) strlen( in );
  31. if ( len == 0 )
  32. return ( in );
  33. /* Trim left */
  34. while ( i < len ) {
  35. if ( isblank( in[i] ) ) {
  36. in[i] = '\0';
  37. start++;
  38. } else
  39. break;
  40. i++;
  41. }
  42. /* Trim right */
  43. i = ( int ) strlen( start ) - 1;
  44. while ( i >= 0 ) {
  45. if ( isblank( start[i] ) )
  46. start[i] = '\0';
  47. else
  48. break;
  49. i--;
  50. }
  51. return ( start );
  52. }
  53. /* Calls trim_string to remove blank space;
  54. Removes paired punctuation delimiters from
  55. beginning and end of string. If the same punctuation
  56. appears first and last (quotes, slashes) they are trimmed;
  57. Also checks for the following pairs: () <> {} [] */
  58. static inline char *
  59. trim_note( char *in )
  60. {
  61. int len;
  62. char *note, start, end;
  63. note = trim_string( in );
  64. if ( note != NULL ) {
  65. len = ( int ) strlen( note );
  66. if ( len > 0 ) {
  67. if ( ispunct( *note ) ) {
  68. start = *note;
  69. end = note[len - 1];
  70. if ( ( start == end )
  71. || ( ( start == '(' ) && ( end == ')' ) )
  72. || ( ( start == '<' ) && ( end == '>' ) )
  73. || ( ( start == '{' ) && ( end == '}' ) )
  74. || ( ( start == '[' ) && ( end == ']' ) ) ) {
  75. note[len - 1] = '\0';
  76. *note = '\0';
  77. note++;
  78. }
  79. }
  80. }
  81. }
  82. return ( note );
  83. }
  84. extern hwi_presets_t _papi_hwi_presets;
  85. static inline int
  86. find_preset_code( char *tmp, int *code )
  87. {
  88. int i = 0;
  89. while ( _papi_hwi_presets.info[i].symbol != NULL ) {
  90. if ( strcasecmp( tmp, _papi_hwi_presets.info[i].symbol ) == 0 ) {
  91. *code = ( int ) ( i | PAPI_PRESET_MASK );
  92. return ( PAPI_OK );
  93. }
  94. i++;
  95. }
  96. return ( PAPI_EINVAL );
  97. }
  98. /* Look for an event file 'name' in a couple common locations.
  99. Return a valid file handle if found */
  100. static FILE *
  101. open_event_table( char *name )
  102. {
  103. FILE *table;
  104. SUBDBG( "Opening %s\n", name );
  105. table = fopen( name, "r" );
  106. if ( table == NULL ) {
  107. SUBDBG( "Open %s failed, trying ./%s.\n", name, PAPI_EVENT_FILE );
  108. sprintf( name, "%s", PAPI_EVENT_FILE );
  109. table = fopen( name, "r" );
  110. }
  111. if ( table == NULL ) {
  112. SUBDBG( "Open ./%s failed, trying ../%s.\n", name, PAPI_EVENT_FILE );
  113. sprintf( name, "../%s", PAPI_EVENT_FILE );
  114. table = fopen( name, "r" );
  115. }
  116. if ( table )
  117. SUBDBG( "Open %s succeeded.\n", name );
  118. return ( table );
  119. }
  120. /* parse a single line from either a file or character table
  121. Strip trailing <cr>; return 0 if empty */
  122. static int
  123. get_event_line( char *line, FILE * table, char **tmp_perfmon_events_table )
  124. {
  125. int ret;
  126. int i;
  127. if ( table ) {
  128. if ( fgets( line, LINE_MAX, table ) ) {
  129. ret = 1;
  130. i = ( int ) strlen( line );
  131. if ( line[i - 1] == '\n' )
  132. line[i - 1] = '\0';
  133. } else
  134. ret = 0;
  135. } else {
  136. for ( i = 0;
  137. **tmp_perfmon_events_table && **tmp_perfmon_events_table != '\n';
  138. i++ ) {
  139. line[i] = **tmp_perfmon_events_table;
  140. ( *tmp_perfmon_events_table )++;
  141. }
  142. if ( **tmp_perfmon_events_table == '\n' ) {
  143. ( *tmp_perfmon_events_table )++;
  144. }
  145. line[i] = '\0';
  146. ret = **tmp_perfmon_events_table;
  147. }
  148. return ( ret );
  149. }
  150. /* Static version of the events file. */
  151. #if defined(STATIC_PAPI_EVENTS_TABLE)
  152. #include "papi_events_table.h"
  153. #else
  154. static char *papi_events_table = NULL;
  155. #endif
  156. #define SHOW_LOADS
  157. static int
  158. load_preset_table( char *pmu_str, int pmu_type,
  159. pfm_preset_search_entry_t * here )
  160. {
  161. char pmu_name[PAPI_MIN_STR_LEN];
  162. char line[LINE_MAX];
  163. char name[PATH_MAX] = "builtin papi_events_table";
  164. char *tmp_papi_events_table = NULL;
  165. char *tmpn;
  166. FILE *table;
  167. int line_no = 1, derived = 0, insert = 0, preset = 0;
  168. int get_presets = 0; /* only get PRESETS after CPU is identified */
  169. int found_presets = 0; /* only terminate search after PRESETS are found */
  170. /* this allows support for synonyms for CPU names */
  171. SUBDBG("ENTER\n");
  172. #ifdef SHOW_LOADS
  173. SUBDBG( "%p\n", here );
  174. #endif
  175. /* copy the pmu identifier, stripping commas if found */
  176. tmpn = pmu_name;
  177. while ( *pmu_str ) {
  178. if ( *pmu_str != ',' )
  179. *tmpn++ = *pmu_str;
  180. pmu_str++;
  181. }
  182. *tmpn = '\0';
  183. /* FIXME -- make sure PAPI_TOT_CYC and PAPI_TOT_INS are #1/#2 */
  184. /* try the environment variable first */
  185. if ( ( tmpn = getenv( "PAPI_CSV_EVENT_FILE" ) ) &&
  186. ( strlen( tmpn ) != 0 ) ) {
  187. sprintf( name, "%s", tmpn );
  188. table = fopen( name, "r" );
  189. }
  190. /* if no valid environment variable, look for built-in table */
  191. else if ( papi_events_table ) {
  192. tmp_papi_events_table = papi_events_table;
  193. table = NULL;
  194. }
  195. /* if no env var and no built-in, search for default file */
  196. else {
  197. #ifdef PAPI_DATADIR
  198. sprintf( name, "%s/%s", PAPI_DATADIR, PAPI_EVENT_FILE );
  199. #else
  200. sprintf( name, "%s", PAPI_EVENT_FILE );
  201. #endif
  202. table = open_event_table( name );
  203. }
  204. /* if no valid file or built-in table, bail */
  205. if ( table == NULL && tmp_papi_events_table == NULL ) {
  206. PAPIERROR
  207. ( "fopen(%s): %s, please set the PAPI_CSV_EVENT_FILE env. variable",
  208. name, strerror( errno ) );
  209. return ( PAPI_ESYS );
  210. }
  211. /* at this point either a valid file pointer or built-in table pointer */
  212. while ( get_event_line( line, table, &tmp_papi_events_table ) ) {
  213. char *t;
  214. int i;
  215. t = trim_string( strtok( line, "," ) );
  216. if ( ( t == NULL ) || ( strlen( t ) == 0 ) )
  217. continue;
  218. if ( t[0] == '#' ) {
  219. /* SUBDBG("Comment found on line %d\n",line_no); */
  220. goto nextline;
  221. } else if ( strcasecmp( t, "CPU" ) == 0 ) {
  222. #ifdef SHOW_LOADS
  223. SUBDBG( "CPU token found on line %d\n", line_no );
  224. #endif
  225. if ( get_presets != 0 && found_presets != 0 ) {
  226. #ifdef SHOW_LOADS
  227. SUBDBG( "Ending preset scanning at line %d of %s.\n", line_no,
  228. name );
  229. #endif
  230. get_presets=0; found_presets=0;
  231. /* goto done; */
  232. }
  233. t = trim_string( strtok( NULL, "," ) );
  234. if ( ( t == NULL ) || ( strlen( t ) == 0 ) ) {
  235. PAPIERROR
  236. ( "Expected name after CPU token at line %d of %s -- ignoring",
  237. line_no, name );
  238. goto nextline;
  239. }
  240. #ifdef SHOW_LOADS
  241. SUBDBG( "Examining CPU (%s) vs. (%s)\n", t, pmu_name );
  242. #endif
  243. if ( strcasecmp( t, pmu_name ) == 0 ) {
  244. int type;
  245. #ifdef SHOW_LOADS
  246. SUBDBG( "Found CPU %s at line %d of %s.\n", t, line_no, name );
  247. #endif
  248. t = trim_string( strtok( NULL, "," ) );
  249. if ( ( t == NULL ) || ( strlen( t ) == 0 ) ) {
  250. #ifdef SHOW_LOADS
  251. SUBDBG
  252. ( "No additional qualifier found, matching on string.\n" );
  253. #endif
  254. get_presets = 1;
  255. } else if ( ( sscanf( t, "%d", &type ) == 1 ) &&
  256. ( type == pmu_type ) ) {
  257. #ifdef SHOW_LOADS
  258. SUBDBG( "Found CPU %s type %d at line %d of %s.\n",
  259. pmu_name, type, line_no, name );
  260. #endif
  261. get_presets = 1;
  262. } else {
  263. #ifdef SHOW_LOADS
  264. SUBDBG( "Additional qualifier match failed %d vs %d.\n",
  265. pmu_type, type );
  266. #endif
  267. }
  268. }
  269. } else if ( strcasecmp( t, "PRESET" ) == 0 ) {
  270. #ifdef SHOW_LOADS
  271. // SUBDBG( "PRESET token found on line %d\n", line_no );
  272. #endif
  273. if ( get_presets == 0 )
  274. goto nextline;
  275. found_presets = 1;
  276. t = trim_string( strtok( NULL, "," ) );
  277. if ( ( t == NULL ) || ( strlen( t ) == 0 ) ) {
  278. PAPIERROR
  279. ( "Expected name after PRESET token at line %d of %s -- ignoring",
  280. line_no, name );
  281. goto nextline;
  282. }
  283. #ifdef SHOW_LOADS
  284. SUBDBG( "Examining preset %s\n", t );
  285. #endif
  286. if ( find_preset_code( t, &preset ) != PAPI_OK ) {
  287. PAPIERROR
  288. ( "Invalid preset name %s after PRESET token at line %d of %s -- ignoring",
  289. t, line_no, name );
  290. goto nextline;
  291. }
  292. SUBDBG( "Found 0x%08x for %s\n", preset, t );
  293. t = trim_string( strtok( NULL, "," ) );
  294. if ( ( t == NULL ) || ( strlen( t ) == 0 ) ) {
  295. PAPIERROR
  296. ( "Expected derived type after PRESET token at line %d of %s -- ignoring",
  297. line_no, name );
  298. goto nextline;
  299. }
  300. #ifdef SHOW_LOADS
  301. SUBDBG( "Examining derived %s\n", t );
  302. #endif
  303. if ( _papi_hwi_derived_type( t, &derived ) != PAPI_OK ) {
  304. PAPIERROR
  305. ( "Invalid derived name %s after PRESET token at line %d of %s -- ignoring",
  306. t, line_no, name );
  307. goto nextline;
  308. }
  309. SUBDBG( "Found %d for %s\n", derived, t );
  310. SUBDBG( "Adding 0x%x,%d to preset search table.\n", preset,
  311. derived );
  312. here[insert].preset = preset;
  313. here[insert].derived = derived;
  314. /* Derived support starts here */
  315. /* Special handling for postfix */
  316. if ( derived == DERIVED_POSTFIX ) {
  317. t = trim_string( strtok( NULL, "," ) );
  318. if ( ( t == NULL ) || ( strlen( t ) == 0 ) ) {
  319. PAPIERROR
  320. ( "Expected Operation string after derived type DERIVED_POSTFIX at line %d of %s -- ignoring",
  321. line_no, name );
  322. goto nextline;
  323. }
  324. #ifdef SHOW_LOADS
  325. SUBDBG( "Saving PostFix operations %s\n", t );
  326. #endif
  327. here[insert].operation = strdup( t );
  328. }
  329. /* All derived terms collected here */
  330. i = 0;
  331. do {
  332. t = trim_string( strtok( NULL, "," ) );
  333. if ( ( t == NULL ) || ( strlen( t ) == 0 ) )
  334. break;
  335. if ( strcasecmp( t, "NOTE" ) == 0 )
  336. break;
  337. here[insert].findme[i] = strdup( t );
  338. #ifdef SHOW_LOADS
  339. SUBDBG( "Adding term (%d) %s to preset event 0x%x.\n", i, t,
  340. preset );
  341. #endif
  342. } while ( ++i < PAPI_MAX_COUNTER_TERMS );
  343. /* End of derived support */
  344. if ( i == 0 ) {
  345. PAPIERROR
  346. ( "Expected PFM event after DERIVED token at line %d of %s -- ignoring",
  347. line_no, name );
  348. goto nextline;
  349. }
  350. if ( i == PAPI_MAX_COUNTER_TERMS )
  351. t = trim_string( strtok( NULL, "," ) );
  352. /* Handle optional NOTEs */
  353. if ( t && ( strcasecmp( t, "NOTE" ) == 0 ) ) {
  354. #ifdef SHOW_LOADS
  355. SUBDBG( "%s found on line %d\n", t, line_no );
  356. #endif
  357. t = trim_note( strtok( NULL, "" ) ); /* read the rest of the line */
  358. if ( ( t == NULL ) || ( strlen( t ) == 0 ) )
  359. PAPIERROR( "Expected Note string at line %d of %s\n",
  360. line_no, name );
  361. else {
  362. here[insert].note = strdup( t );
  363. #ifdef SHOW_LOADS
  364. SUBDBG( "NOTE: --%s-- found on line %d\n", t, line_no );
  365. #endif
  366. }
  367. }
  368. insert++;
  369. SUBDBG( "# events inserted: --%d-- \n", insert );
  370. } else {
  371. PAPIERROR( "Unrecognized token %s at line %d of %s -- ignoring", t,
  372. line_no, name );
  373. goto nextline;
  374. }
  375. nextline:
  376. line_no++;
  377. }
  378. /* done: */
  379. if ( table )
  380. fclose( table );
  381. return PAPI_OK;
  382. }
  383. /* Frees memory for all the strdup'd char strings in a preset string array.
  384. Assumes the array is initialized to 0 and has at least one 0 entry at the end.
  385. free()ing a NULL pointer is a NOP. */
  386. static void
  387. free_preset_table( pfm_preset_search_entry_t * here )
  388. {
  389. int i = 0, j;
  390. while ( here[i].preset ) {
  391. for ( j = 0; j < PAPI_MAX_COUNTER_TERMS; j++ )
  392. free( here[i].findme[j] );
  393. free( here[i].operation );
  394. free( here[i].note );
  395. i++;
  396. }
  397. }
  398. static void
  399. free_notes( hwi_dev_notes_t * here )
  400. {
  401. int i = 0;
  402. while ( here[i].event_code ) {
  403. free( here[i].dev_note );
  404. i++;
  405. }
  406. }
  407. static int
  408. generate_preset_search_map( hwi_search_t ** maploc, hwi_dev_notes_t ** noteloc,
  409. pfm_preset_search_entry_t * strmap )
  410. {
  411. int k = 0, term;
  412. unsigned int i = 0, j = 0;
  413. hwi_search_t *psmap;
  414. hwi_dev_notes_t *notemap;
  415. int event_idx;
  416. /* Count up the proposed presets */
  417. while ( strmap[i].preset ) {
  418. i++;
  419. }
  420. SUBDBG( "generate_preset_search_map(%p,%p,%p) %d proposed presets\n",
  421. maploc, noteloc, strmap, i );
  422. i++;
  423. /* Add null entry */
  424. psmap = ( hwi_search_t * ) malloc( i * sizeof ( hwi_search_t ) );
  425. if ( psmap == NULL ) {
  426. return PAPI_ENOMEM;
  427. }
  428. notemap = ( hwi_dev_notes_t * ) malloc( i * sizeof ( hwi_dev_notes_t ) );
  429. if ( notemap == NULL ) {
  430. free(psmap);
  431. return PAPI_ENOMEM;
  432. }
  433. memset( psmap, 0x0, i * sizeof ( hwi_search_t ) );
  434. memset( notemap, 0x0, i * sizeof ( hwi_dev_notes_t ) );
  435. i = 0;
  436. while ( strmap[i].preset ) {
  437. /* Handle derived events */
  438. term = 0;
  439. do {
  440. int ret;
  441. SUBDBG("Looking up: %s\n",strmap[i].findme[term]);
  442. ret=_papi_hwi_native_name_to_code(strmap[i].findme[term],
  443. &event_idx);
  444. if (ret==PAPI_OK) {
  445. SUBDBG("Found %x\n",event_idx);
  446. psmap[j].data.native[term]=event_idx;
  447. term++;
  448. }
  449. else {
  450. SUBDBG("Error finding event %x\n",event_idx);
  451. break;
  452. }
  453. } while ( strmap[i].findme[term] != NULL &&
  454. term < PAPI_MAX_COUNTER_TERMS );
  455. /* terminate the native term array with PAPI_NULL */
  456. if ( term < PAPI_MAX_COUNTER_TERMS ) {
  457. psmap[j].data.native[term] = PAPI_NULL;
  458. }
  459. //if ( ret == PAPI_OK ) {
  460. psmap[j].event_code = ( unsigned int ) strmap[i].preset;
  461. psmap[j].data.derived = strmap[i].derived;
  462. if ( strmap[i].derived == DERIVED_POSTFIX ) {
  463. strncpy( psmap[j].data.operation, strmap[i].operation,
  464. PAPI_MIN_STR_LEN );
  465. }
  466. if ( strmap[i].note ) {
  467. notemap[k].event_code = ( unsigned int ) strmap[i].preset;
  468. notemap[k].dev_note = strdup( strmap[i].note );
  469. k++;
  470. }
  471. j++;
  472. //}
  473. i++;
  474. }
  475. if ( i != j ) {
  476. PAPIERROR( "%d of %d events in %s were not valid", i - j, i,
  477. PAPI_EVENT_FILE );
  478. }
  479. SUBDBG( "generate_preset_search_map(%p,%p,%p) %d actual presets\n", maploc,
  480. noteloc, strmap, j );
  481. *maploc = psmap;
  482. *noteloc = notemap;
  483. return PAPI_OK;
  484. }
  485. int
  486. _papi_libpfm_setup_presets( char *pmu_name, int pmu_type )
  487. {
  488. int retval;
  489. hwi_search_t *preset_search_map = NULL;
  490. hwi_dev_notes_t *notemap = NULL;
  491. pfm_preset_search_entry_t *_perfmon2_pfm_preset_search_map;
  492. /* allocate and clear array of search string structures */
  493. _perfmon2_pfm_preset_search_map =
  494. malloc( sizeof ( pfm_preset_search_entry_t ) * PAPI_MAX_PRESET_EVENTS );
  495. if ( _perfmon2_pfm_preset_search_map == NULL )
  496. return PAPI_ENOMEM;
  497. memset( _perfmon2_pfm_preset_search_map, 0x0,
  498. sizeof ( pfm_preset_search_entry_t ) * PAPI_MAX_PRESET_EVENTS );
  499. retval = load_preset_table( pmu_name, pmu_type,
  500. _perfmon2_pfm_preset_search_map );
  501. if (retval) goto out1;
  502. retval = generate_preset_search_map( &preset_search_map, &notemap,
  503. _perfmon2_pfm_preset_search_map );
  504. if (retval) goto out;
  505. retval = _papi_hwi_setup_all_presets( preset_search_map, notemap );
  506. out:
  507. free( preset_search_map );
  508. free_notes( notemap );
  509. free( notemap );
  510. out1:
  511. free_preset_table( _perfmon2_pfm_preset_search_map );
  512. free( _perfmon2_pfm_preset_search_map );
  513. return retval;
  514. }