hwcfuncs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /* Copyright (C) 2021 Free Software Foundation, Inc.
  2. Contributed by Oracle.
  3. This file is part of GNU Binutils.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, 51 Franklin Street - Fifth Floor, Boston,
  15. MA 02110-1301, USA. */
  16. /* Hardware counter profiling */
  17. #include "hwcdrv.h"
  18. #include "hwcfuncs.h"
  19. /*---------------------------------------------------------------------------*/
  20. /* macros */
  21. #define IS_GLOBAL /* Mark global symbols */
  22. #define HWCDRV_API static /* Mark functions used by hwcdrv API */
  23. /*---------------------------------------------------------------------------*/
  24. /* static variables */
  25. static uint_t cpcN_npics;
  26. static char hwcfuncs_errmsg_buf[1024];
  27. static int hwcfuncs_errmsg_enabled = 1;
  28. static int hwcfuncs_errmsg_valid;
  29. /* --- user counter selections and options */
  30. static unsigned hwcdef_cnt; /* number of *active* hardware counters */
  31. static Hwcentry hwcdef[MAX_PICS]; /* HWC definitions */
  32. static Hwcentry *hwctable[MAX_PICS]; /* HWC definitions */
  33. /* --- drivers --- */
  34. // default driver
  35. HWCDRV_API int
  36. hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int* tsd_sz)
  37. {
  38. return -1;
  39. }
  40. HWCDRV_API void
  41. hwcdrv_get_info (
  42. int * cpuver, const char ** cciname,
  43. uint_t * npics, const char ** docref, uint64_t* support) { }
  44. HWCDRV_API int
  45. hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
  46. {
  47. return -1;
  48. }
  49. HWCDRV_API int
  50. hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_find_action,
  51. hwcf_attr_cb_t *attr_find_action)
  52. {
  53. return 0;
  54. }
  55. HWCDRV_API int
  56. hwcdrv_assign_regnos (Hwcentry *entries[], unsigned numctrs)
  57. {
  58. return -1;
  59. }
  60. HWCDRV_API int
  61. hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
  62. {
  63. return -1;
  64. }
  65. HWCDRV_API int
  66. hwcdrv_read_events (hwc_event_t *events, hwc_event_samples_t*samples)
  67. {
  68. return -1;
  69. }
  70. HWCDRV_API int
  71. hwcdrv_start (void)
  72. {
  73. return -1;
  74. }
  75. HWCDRV_API int
  76. hwcdrv_overflow (siginfo_t *si, hwc_event_t *s, hwc_event_t *t)
  77. {
  78. return 0;
  79. }
  80. HWCDRV_API int
  81. hwcdrv_sighlr_restart (const hwc_event_t *sample)
  82. {
  83. return -1;
  84. }
  85. HWCDRV_API int
  86. hwcdrv_lwp_suspend (void)
  87. {
  88. return -1;
  89. }
  90. HWCDRV_API int
  91. hwcdrv_lwp_resume (void)
  92. {
  93. return -1;
  94. }
  95. HWCDRV_API int
  96. hwcdrv_free_counters (void)
  97. {
  98. return 0;
  99. }
  100. HWCDRV_API int
  101. hwcdrv_lwp_init (void)
  102. {
  103. return 0;
  104. }
  105. HWCDRV_API void
  106. hwcdrv_lwp_fini (void) { }
  107. static hwcdrv_api_t hwcdrv_default = {
  108. hwcdrv_init,
  109. hwcdrv_get_info,
  110. hwcdrv_enable_mt,
  111. hwcdrv_get_descriptions,
  112. hwcdrv_assign_regnos,
  113. hwcdrv_create_counters,
  114. hwcdrv_start,
  115. hwcdrv_overflow,
  116. hwcdrv_read_events,
  117. hwcdrv_sighlr_restart,
  118. hwcdrv_lwp_suspend,
  119. hwcdrv_lwp_resume,
  120. hwcdrv_free_counters,
  121. hwcdrv_lwp_init,
  122. hwcdrv_lwp_fini,
  123. -1 // hwcdrv_init_status
  124. };
  125. static hwcdrv_api_t *hwcdrv_driver = &hwcdrv_default;
  126. /*---------------------------------------------------------------------------*/
  127. /* misc */
  128. /* print a counter definition (for debugging) */
  129. static void
  130. ctrdefprint (int dbg_lvl, const char * hdr, Hwcentry*phwcdef)
  131. {
  132. TprintfT (dbg_lvl, "%s: name='%s', int_name='%s',"
  133. " reg_num=%d, timecvt=%d, memop=%d, "
  134. "interval=%d, tag=%u, reg_list=%p\n",
  135. hdr, phwcdef->name, phwcdef->int_name, phwcdef->reg_num,
  136. phwcdef->timecvt, phwcdef->memop, phwcdef->val,
  137. phwcdef->sort_order, phwcdef->reg_list);
  138. }
  139. /*---------------------------------------------------------------------------*/
  140. /* errmsg buffering */
  141. /* errmsg buffering is needed only because the most descriptive error
  142. messages from CPC are delivered using a callback mechanism.
  143. hwcfuncs_errmsg_get() should only be used during initialization, and
  144. ideally, only to provide feedback to an end user when his counters can't
  145. be bound to HW.
  146. */
  147. IS_GLOBAL char *
  148. hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
  149. {
  150. hwcfuncs_errmsg_enabled = 0;
  151. if (buf && bufsize)
  152. {
  153. if (hwcfuncs_errmsg_valid)
  154. {
  155. strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
  156. buf[bufsize - 1] = 0;
  157. }
  158. else
  159. *buf = 0;
  160. }
  161. hwcfuncs_errmsg_buf[0] = 0;
  162. hwcfuncs_errmsg_valid = 0;
  163. hwcfuncs_errmsg_enabled = enable;
  164. return buf;
  165. }
  166. /* used by cpc to log an error */
  167. IS_GLOBAL void
  168. hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
  169. const char *fmt, va_list ap)
  170. {
  171. if (hwcfuncs_errmsg_enabled &&
  172. !hwcfuncs_errmsg_valid)
  173. {
  174. vsnprintf (hwcfuncs_errmsg_buf, sizeof (hwcfuncs_errmsg_buf), fmt, ap);
  175. TprintfT (DBG_LT0, "hwcfuncs: cpcN_capture_errmsg(): %s\n",
  176. hwcfuncs_errmsg_buf);
  177. hwcfuncs_errmsg_valid = 1;
  178. }
  179. return;
  180. }
  181. /* Log an internal error to the CPC error buffer.
  182. * Note: only call this during init functions.
  183. * Note: when most cpc calls fail, they will call cpcN_capture_errmsg()
  184. * directly, so only call logerr() when a non-cpc function fails.
  185. */
  186. IS_GLOBAL void
  187. hwcfuncs_int_logerr (const char *format, ...)
  188. {
  189. va_list va;
  190. va_start (va, format);
  191. hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
  192. va_end (va);
  193. }
  194. /* utils to parse counter strings */
  195. static void
  196. clear_hwcdefs ()
  197. {
  198. for (unsigned idx = 0; idx < MAX_PICS; idx++)
  199. {
  200. static Hwcentry empty;
  201. hwcdef[idx] = empty; // leaks strings and reg_list array
  202. hwcdef[idx].reg_num = REGNO_ANY;
  203. hwcdef[idx].val = -1;
  204. hwcdef[idx].sort_order = -1;
  205. }
  206. }
  207. /* initialize hwcdef[] based on user's counter definitions */
  208. static int
  209. process_data_descriptor (const char *defstring)
  210. {
  211. /*
  212. * <defstring> format should be of format
  213. * :%s:%s:0x%x:%d:%lld:%d:%d:0x%x[,%s...repeat for each ctr]
  214. * where the counter fields are:
  215. * :<userName>:<internalCtr>:<register>:<timeoutVal>[:m<min_time>]:<tag>:<timecvt>:<memop>
  216. * See Coll_Ctrl::build_data_desc().
  217. */
  218. int err = 0;
  219. char *ds = NULL;
  220. char *dsp = NULL;
  221. unsigned idx;
  222. clear_hwcdefs ();
  223. if (!defstring || !strlen (defstring))
  224. {
  225. err = HWCFUNCS_ERROR_HWCARGS;
  226. goto ext_hw_install_end;
  227. }
  228. ds = strdup (defstring);
  229. if (!ds)
  230. {
  231. err = HWCFUNCS_ERROR_HWCINIT;
  232. goto ext_hw_install_end;
  233. }
  234. dsp = ds;
  235. for (idx = 0; idx < MAX_PICS && *dsp; idx++)
  236. {
  237. char *name = NULL;
  238. char *int_name = NULL;
  239. regno_t reg = REGNO_ANY;
  240. ABST_type memop = ABST_NONE;
  241. int interval = 0;
  242. int timecvt = 0;
  243. unsigned sort_order = (unsigned) - 1;
  244. /* name */
  245. name = dsp;
  246. dsp = strchr (dsp, ':');
  247. if (dsp == NULL)
  248. {
  249. err = HWCFUNCS_ERROR_HWCARGS;
  250. goto ext_hw_install_end;
  251. }
  252. *dsp++ = (char) 0;
  253. /* int_name */
  254. int_name = dsp;
  255. dsp = strchr (dsp, ':');
  256. if (dsp == NULL)
  257. {
  258. err = HWCFUNCS_ERROR_HWCARGS;
  259. goto ext_hw_install_end;
  260. }
  261. *dsp++ = (char) 0;
  262. /* reg_num */
  263. reg = (int) strtol (dsp, &dsp, 0);
  264. if (*dsp++ != ':')
  265. {
  266. err = HWCFUNCS_ERROR_HWCARGS;
  267. goto ext_hw_install_end;
  268. }
  269. if (reg < 0 && reg != -1)
  270. {
  271. err = HWCFUNCS_ERROR_HWCARGS;
  272. goto ext_hw_install_end;
  273. }
  274. if (reg >= 0)
  275. hwcdef[idx].reg_num = reg;
  276. /* val */
  277. interval = (int) strtol (dsp, &dsp, 0);
  278. if (*dsp++ != ':')
  279. {
  280. err = HWCFUNCS_ERROR_HWCARGS;
  281. goto ext_hw_install_end;
  282. }
  283. if (interval < 0)
  284. {
  285. err = HWCFUNCS_ERROR_HWCARGS;
  286. goto ext_hw_install_end;
  287. }
  288. hwcdef[idx].val = interval;
  289. /* min_time */
  290. /*
  291. * This is a new field.
  292. * An old launcher (dbx, etc.) would not include it.
  293. * Detect the presence of the field by the char 'm'.
  294. */
  295. if (*dsp == 'm')
  296. {
  297. long long tmp_ll = 0;
  298. dsp++;
  299. tmp_ll = strtoll (dsp, &dsp, 0);
  300. if (*dsp++ != ':')
  301. {
  302. err = HWCFUNCS_ERROR_HWCARGS;
  303. goto ext_hw_install_end;
  304. }
  305. if (tmp_ll < 0)
  306. {
  307. err = HWCFUNCS_ERROR_HWCARGS;
  308. goto ext_hw_install_end;
  309. }
  310. hwcdef[idx].min_time = tmp_ll;
  311. }
  312. else
  313. hwcdef[idx].min_time = 0;
  314. /* sort_order */
  315. sort_order = (int) strtoul (dsp, &dsp, 0);
  316. if (*dsp++ != ':')
  317. {
  318. err = HWCFUNCS_ERROR_HWCARGS;
  319. goto ext_hw_install_end;
  320. }
  321. hwcdef[idx].sort_order = sort_order;
  322. /* timecvt */
  323. timecvt = (int) strtol (dsp, &dsp, 0);
  324. if (*dsp++ != ':')
  325. {
  326. err = HWCFUNCS_ERROR_HWCARGS;
  327. goto ext_hw_install_end;
  328. }
  329. hwcdef[idx].timecvt = timecvt;
  330. /* memop */
  331. memop = (ABST_type) strtol (dsp, &dsp, 0);
  332. if (*dsp != 0 && *dsp++ != ',')
  333. {
  334. err = HWCFUNCS_ERROR_HWCARGS;
  335. goto ext_hw_install_end;
  336. }
  337. hwcdef[idx].memop = memop;
  338. if (*name)
  339. hwcdef[idx].name = strdup (name);
  340. else
  341. hwcdef[idx].name = strdup (int_name);
  342. if (*int_name)
  343. hwcdef[idx].int_name = strdup (int_name);
  344. else
  345. hwcdef[idx].int_name = strdup (name);
  346. ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
  347. }
  348. if (*dsp)
  349. {
  350. TprintfT (DBG_LT0, "hwcfuncs: ERROR: process_data_descriptor(): "
  351. "ctr string had some trailing garbage:"
  352. " '%s'\n", dsp);
  353. err = HWCFUNCS_ERROR_HWCARGS;
  354. goto ext_hw_install_end;
  355. }
  356. free (ds);
  357. hwcdef_cnt = idx;
  358. return 0;
  359. ext_hw_install_end:
  360. if (dsp && *dsp)
  361. {
  362. TprintfT (DBG_LT0, "hwcfuncs: ERROR: process_data_descriptor(): "
  363. " syntax error just before:"
  364. " '%s;\n", dsp);
  365. logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
  366. }
  367. else
  368. logerr (GTXT ("Data descriptor syntax error\n"));
  369. free (ds);
  370. return err;
  371. }
  372. /* initialize hwcdef[] based on user's counter definitions */
  373. static int
  374. process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
  375. {
  376. int err = 0;
  377. clear_hwcdefs ();
  378. if (numctrs > cpcN_npics)
  379. {
  380. logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
  381. return HWCFUNCS_ERROR_HWCARGS;
  382. }
  383. for (unsigned idx = 0; idx < numctrs; idx++)
  384. {
  385. Hwcentry *phwcdef = &hwcdef[idx];
  386. *phwcdef = *entries[idx];
  387. if (phwcdef->name)
  388. phwcdef->name = strdup (phwcdef->name);
  389. else
  390. phwcdef->name = "NULL";
  391. if (phwcdef->int_name)
  392. phwcdef->int_name = strdup (phwcdef->int_name);
  393. else
  394. phwcdef->int_name = "NULL";
  395. if (phwcdef->val < 0)
  396. {
  397. logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
  398. phwcdef->name);
  399. err = HWCFUNCS_ERROR_HWCARGS;
  400. break;
  401. }
  402. ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
  403. }
  404. if (!err)
  405. hwcdef_cnt = numctrs;
  406. return err;
  407. }
  408. /* see hwcfuncs.h */
  409. IS_GLOBAL void *
  410. hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
  411. unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
  412. {
  413. char *head = NULL;
  414. char *tail = NULL;
  415. uint_t nattrs = 0;
  416. char *counter_copy;
  417. int success = 0;
  418. char errbuf[512];
  419. errbuf[0] = 0;
  420. counter_copy = strdup (countername);
  421. /* advance pointer to first attribute */
  422. tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
  423. if (tail)
  424. *tail = 0;
  425. /* remove regno and value, if supplied */
  426. {
  427. char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
  428. if (tmp)
  429. *tmp = 0;
  430. tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
  431. if (tmp)
  432. *tmp = 0;
  433. }
  434. while (tail)
  435. {
  436. char *pch;
  437. if (nattrs >= max_attrs)
  438. {
  439. snprintf (errbuf, sizeof (errbuf),
  440. GTXT ("Too many attributes defined in `%s'"),
  441. countername);
  442. goto mycpc2_parse_attrs_end;
  443. }
  444. /* get attribute name */
  445. head = tail + 1;
  446. tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
  447. if (!tail)
  448. {
  449. snprintf (errbuf, sizeof (errbuf),
  450. GTXT ("Missing value for attribute `%s' in `%s'"),
  451. head, countername);
  452. goto mycpc2_parse_attrs_end;
  453. }
  454. *tail = 0; /* null terminate current component */
  455. attrs[nattrs].ca_name = head;
  456. /* get attribute value */
  457. head = tail + 1;
  458. tail = strchr (head, HWCFUNCS_PARSE_ATTR);
  459. if (tail)
  460. *tail = 0; /* null terminate current component */
  461. attrs[nattrs].ca_val = strtoull (head, &pch, 0);
  462. if (pch == head)
  463. {
  464. snprintf (errbuf, sizeof (errbuf),
  465. GTXT ("Illegal value for attribute `%s' in `%s'"),
  466. attrs[nattrs].ca_name, countername);
  467. goto mycpc2_parse_attrs_end;
  468. }
  469. TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
  470. " '%s' = 0x%llx\n",
  471. counter_copy, nattrs, attrs[nattrs].ca_name,
  472. (long long unsigned int) attrs[nattrs].ca_val);
  473. nattrs++;
  474. }
  475. success = 1;
  476. mycpc2_parse_attrs_end:
  477. *pnum_attrs = nattrs;
  478. if (success)
  479. {
  480. if (errstring)
  481. *errstring = NULL;
  482. }
  483. else
  484. {
  485. if (errstring)
  486. *errstring = strdup (errbuf);
  487. free (counter_copy);
  488. counter_copy = NULL;
  489. }
  490. return counter_copy;
  491. }
  492. IS_GLOBAL void
  493. hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
  494. char **pattrs, char **pregstr, regno_t *pregno)
  495. {
  496. char *nameptr, *copy, *slash, *attr_delim;
  497. int plus;
  498. regno_t regno;
  499. nameptr = copy = strdup (counter_def);
  500. /* plus */
  501. plus = 0;
  502. if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
  503. {
  504. plus = 1;
  505. nameptr++;
  506. }
  507. else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
  508. {
  509. plus = -1;
  510. nameptr++;
  511. }
  512. if (pplus)
  513. *pplus = plus;
  514. /* regno */
  515. regno = REGNO_ANY;
  516. if (pregstr)
  517. *pregstr = NULL;
  518. slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
  519. if (slash != NULL)
  520. {
  521. /* the remaining string should be a number > 0 */
  522. if (pregstr)
  523. *pregstr = strdup (slash);
  524. char *endchar = NULL;
  525. regno = (regno_t) strtol (slash + 1, &endchar, 0);
  526. if (*endchar != 0)
  527. regno = -2;
  528. if (*(slash + 1) == '-')
  529. regno = -2;
  530. /* terminate previous element up to slash */
  531. *slash = 0;
  532. }
  533. if (pregno)
  534. *pregno = regno;
  535. /* attrs */
  536. if (pattrs)
  537. *pattrs = NULL;
  538. attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
  539. if (attr_delim != NULL)
  540. {
  541. if (pattrs)
  542. *pattrs = strdup (attr_delim);
  543. /* terminate previous element up to attr_delim */
  544. *attr_delim++ = 0;
  545. }
  546. if (pnameOnly)
  547. *pnameOnly = strdup (nameptr);
  548. free (copy);
  549. }
  550. /* create counters */
  551. IS_GLOBAL int
  552. hwcfuncs_bind_descriptor (const char *defstring)
  553. {
  554. int err = process_data_descriptor (defstring);
  555. if (err)
  556. {
  557. TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
  558. return err;
  559. }
  560. err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
  561. return err;
  562. }
  563. /* see hwcfuncs.h */
  564. IS_GLOBAL int
  565. hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
  566. {
  567. int err = -1;
  568. err = process_hwcentrylist (entries, numctrs);
  569. if (err)
  570. {
  571. TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
  572. return err;
  573. }
  574. err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
  575. return err;
  576. }
  577. /* see hwcfuncs.h */
  578. IS_GLOBAL Hwcentry **
  579. hwcfuncs_get_ctrs (unsigned *defcnt)
  580. {
  581. if (defcnt)
  582. *defcnt = hwcdef_cnt;
  583. return hwctable;
  584. }
  585. /* return 1 if <regno> is in Hwcentry's list */
  586. IS_GLOBAL int
  587. regno_is_valid (const Hwcentry * pctr, regno_t regno)
  588. {
  589. regno_t *reg_list = pctr->reg_list;
  590. if (REG_LIST_IS_EMPTY (reg_list))
  591. return 0;
  592. if (regno == REGNO_ANY) /* wildcard */
  593. return 1;
  594. for (int ii = 0; ii < MAX_PICS; ii++)
  595. {
  596. regno_t tmp = reg_list[ii];
  597. if (REG_LIST_EOL (tmp)) /* end of list */
  598. break;
  599. if (tmp == regno) /* is in list */
  600. return 1;
  601. }
  602. return 0;
  603. }
  604. /* supplied by hwcdrv_api drivers */
  605. IS_GLOBAL int
  606. hwcfuncs_assign_regnos (Hwcentry* entries[],
  607. unsigned numctrs)
  608. {
  609. if (numctrs > cpcN_npics)
  610. {
  611. logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
  612. return HWCFUNCS_ERROR_HWCARGS;
  613. }
  614. return hwcdrv_driver->hwcdrv_assign_regnos (entries, numctrs);
  615. }
  616. extern hwcdrv_api_t hwcdrv_pcl_api;
  617. static int hwcdrv_driver_inited = 0;
  618. hwcdrv_api_t *
  619. get_hwcdrv ()
  620. {
  621. if (hwcdrv_driver_inited)
  622. return hwcdrv_driver;
  623. hwcdrv_driver_inited = 1;
  624. cpcN_npics = 0;
  625. for (int i = 0; i < MAX_PICS; i++)
  626. hwctable[i] = &hwcdef[i];
  627. hwcdrv_driver = &hwcdrv_pcl_api;
  628. hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
  629. if (hwcdrv_driver->hwcdrv_init_status == 0)
  630. {
  631. hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
  632. return hwcdrv_driver;
  633. }
  634. hwcdrv_driver = &hwcdrv_default;
  635. return hwcdrv_driver;
  636. }