pmu.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. #include <linux/list.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <dirent.h>
  6. #include <api/fs/fs.h>
  7. #include <locale.h>
  8. #include "util.h"
  9. #include "pmu.h"
  10. #include "parse-events.h"
  11. #include "cpumap.h"
  12. #define UNIT_MAX_LEN 31 /* max length for event unit name */
  13. struct perf_pmu_alias {
  14. char *name;
  15. struct list_head terms;
  16. struct list_head list;
  17. char unit[UNIT_MAX_LEN+1];
  18. double scale;
  19. };
  20. struct perf_pmu_format {
  21. char *name;
  22. int value;
  23. DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
  24. struct list_head list;
  25. };
  26. #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
  27. int perf_pmu_parse(struct list_head *list, char *name);
  28. extern FILE *perf_pmu_in;
  29. static LIST_HEAD(pmus);
  30. /*
  31. * Parse & process all the sysfs attributes located under
  32. * the directory specified in 'dir' parameter.
  33. */
  34. int perf_pmu__format_parse(char *dir, struct list_head *head)
  35. {
  36. struct dirent *evt_ent;
  37. DIR *format_dir;
  38. int ret = 0;
  39. format_dir = opendir(dir);
  40. if (!format_dir)
  41. return -EINVAL;
  42. while (!ret && (evt_ent = readdir(format_dir))) {
  43. char path[PATH_MAX];
  44. char *name = evt_ent->d_name;
  45. FILE *file;
  46. if (!strcmp(name, ".") || !strcmp(name, ".."))
  47. continue;
  48. snprintf(path, PATH_MAX, "%s/%s", dir, name);
  49. ret = -EINVAL;
  50. file = fopen(path, "r");
  51. if (!file)
  52. break;
  53. perf_pmu_in = file;
  54. ret = perf_pmu_parse(head, name);
  55. fclose(file);
  56. }
  57. closedir(format_dir);
  58. return ret;
  59. }
  60. /*
  61. * Reading/parsing the default pmu format definition, which should be
  62. * located at:
  63. * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
  64. */
  65. static int pmu_format(const char *name, struct list_head *format)
  66. {
  67. struct stat st;
  68. char path[PATH_MAX];
  69. const char *sysfs = sysfs__mountpoint();
  70. if (!sysfs)
  71. return -1;
  72. snprintf(path, PATH_MAX,
  73. "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
  74. if (stat(path, &st) < 0)
  75. return 0; /* no error if format does not exist */
  76. if (perf_pmu__format_parse(path, format))
  77. return -1;
  78. return 0;
  79. }
  80. static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
  81. {
  82. struct stat st;
  83. ssize_t sret;
  84. char scale[128];
  85. int fd, ret = -1;
  86. char path[PATH_MAX];
  87. const char *lc;
  88. snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
  89. fd = open(path, O_RDONLY);
  90. if (fd == -1)
  91. return -1;
  92. if (fstat(fd, &st) < 0)
  93. goto error;
  94. sret = read(fd, scale, sizeof(scale)-1);
  95. if (sret < 0)
  96. goto error;
  97. scale[sret] = '\0';
  98. /*
  99. * save current locale
  100. */
  101. lc = setlocale(LC_NUMERIC, NULL);
  102. /*
  103. * force to C locale to ensure kernel
  104. * scale string is converted correctly.
  105. * kernel uses default C locale.
  106. */
  107. setlocale(LC_NUMERIC, "C");
  108. alias->scale = strtod(scale, NULL);
  109. /* restore locale */
  110. setlocale(LC_NUMERIC, lc);
  111. ret = 0;
  112. error:
  113. close(fd);
  114. return ret;
  115. }
  116. static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
  117. {
  118. char path[PATH_MAX];
  119. ssize_t sret;
  120. int fd;
  121. snprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
  122. fd = open(path, O_RDONLY);
  123. if (fd == -1)
  124. return -1;
  125. sret = read(fd, alias->unit, UNIT_MAX_LEN);
  126. if (sret < 0)
  127. goto error;
  128. close(fd);
  129. alias->unit[sret] = '\0';
  130. return 0;
  131. error:
  132. close(fd);
  133. alias->unit[0] = '\0';
  134. return -1;
  135. }
  136. static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
  137. {
  138. struct perf_pmu_alias *alias;
  139. char buf[256];
  140. int ret;
  141. ret = fread(buf, 1, sizeof(buf), file);
  142. if (ret == 0)
  143. return -EINVAL;
  144. buf[ret] = 0;
  145. alias = malloc(sizeof(*alias));
  146. if (!alias)
  147. return -ENOMEM;
  148. INIT_LIST_HEAD(&alias->terms);
  149. alias->scale = 1.0;
  150. alias->unit[0] = '\0';
  151. ret = parse_events_terms(&alias->terms, buf);
  152. if (ret) {
  153. free(alias);
  154. return ret;
  155. }
  156. alias->name = strdup(name);
  157. /*
  158. * load unit name and scale if available
  159. */
  160. perf_pmu__parse_unit(alias, dir, name);
  161. perf_pmu__parse_scale(alias, dir, name);
  162. list_add_tail(&alias->list, list);
  163. return 0;
  164. }
  165. /*
  166. * Process all the sysfs attributes located under the directory
  167. * specified in 'dir' parameter.
  168. */
  169. static int pmu_aliases_parse(char *dir, struct list_head *head)
  170. {
  171. struct dirent *evt_ent;
  172. DIR *event_dir;
  173. size_t len;
  174. int ret = 0;
  175. event_dir = opendir(dir);
  176. if (!event_dir)
  177. return -EINVAL;
  178. while (!ret && (evt_ent = readdir(event_dir))) {
  179. char path[PATH_MAX];
  180. char *name = evt_ent->d_name;
  181. FILE *file;
  182. if (!strcmp(name, ".") || !strcmp(name, ".."))
  183. continue;
  184. /*
  185. * skip .unit and .scale info files
  186. * parsed in perf_pmu__new_alias()
  187. */
  188. len = strlen(name);
  189. if (len > 5 && !strcmp(name + len - 5, ".unit"))
  190. continue;
  191. if (len > 6 && !strcmp(name + len - 6, ".scale"))
  192. continue;
  193. snprintf(path, PATH_MAX, "%s/%s", dir, name);
  194. ret = -EINVAL;
  195. file = fopen(path, "r");
  196. if (!file)
  197. break;
  198. ret = perf_pmu__new_alias(head, dir, name, file);
  199. fclose(file);
  200. }
  201. closedir(event_dir);
  202. return ret;
  203. }
  204. /*
  205. * Reading the pmu event aliases definition, which should be located at:
  206. * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
  207. */
  208. static int pmu_aliases(const char *name, struct list_head *head)
  209. {
  210. struct stat st;
  211. char path[PATH_MAX];
  212. const char *sysfs = sysfs__mountpoint();
  213. if (!sysfs)
  214. return -1;
  215. snprintf(path, PATH_MAX,
  216. "%s/bus/event_source/devices/%s/events", sysfs, name);
  217. if (stat(path, &st) < 0)
  218. return 0; /* no error if 'events' does not exist */
  219. if (pmu_aliases_parse(path, head))
  220. return -1;
  221. return 0;
  222. }
  223. static int pmu_alias_terms(struct perf_pmu_alias *alias,
  224. struct list_head *terms)
  225. {
  226. struct parse_events_term *term, *cloned;
  227. LIST_HEAD(list);
  228. int ret;
  229. list_for_each_entry(term, &alias->terms, list) {
  230. ret = parse_events_term__clone(&cloned, term);
  231. if (ret) {
  232. parse_events__free_terms(&list);
  233. return ret;
  234. }
  235. list_add_tail(&cloned->list, &list);
  236. }
  237. list_splice(&list, terms);
  238. return 0;
  239. }
  240. /*
  241. * Reading/parsing the default pmu type value, which should be
  242. * located at:
  243. * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
  244. */
  245. static int pmu_type(const char *name, __u32 *type)
  246. {
  247. struct stat st;
  248. char path[PATH_MAX];
  249. FILE *file;
  250. int ret = 0;
  251. const char *sysfs = sysfs__mountpoint();
  252. if (!sysfs)
  253. return -1;
  254. snprintf(path, PATH_MAX,
  255. "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
  256. if (stat(path, &st) < 0)
  257. return -1;
  258. file = fopen(path, "r");
  259. if (!file)
  260. return -EINVAL;
  261. if (1 != fscanf(file, "%u", type))
  262. ret = -1;
  263. fclose(file);
  264. return ret;
  265. }
  266. /* Add all pmus in sysfs to pmu list: */
  267. static void pmu_read_sysfs(void)
  268. {
  269. char path[PATH_MAX];
  270. DIR *dir;
  271. struct dirent *dent;
  272. const char *sysfs = sysfs__mountpoint();
  273. if (!sysfs)
  274. return;
  275. snprintf(path, PATH_MAX,
  276. "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
  277. dir = opendir(path);
  278. if (!dir)
  279. return;
  280. while ((dent = readdir(dir))) {
  281. if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
  282. continue;
  283. /* add to static LIST_HEAD(pmus): */
  284. perf_pmu__find(dent->d_name);
  285. }
  286. closedir(dir);
  287. }
  288. static struct cpu_map *pmu_cpumask(const char *name)
  289. {
  290. struct stat st;
  291. char path[PATH_MAX];
  292. FILE *file;
  293. struct cpu_map *cpus;
  294. const char *sysfs = sysfs__mountpoint();
  295. if (!sysfs)
  296. return NULL;
  297. snprintf(path, PATH_MAX,
  298. "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
  299. if (stat(path, &st) < 0)
  300. return NULL;
  301. file = fopen(path, "r");
  302. if (!file)
  303. return NULL;
  304. cpus = cpu_map__read(file);
  305. fclose(file);
  306. return cpus;
  307. }
  308. static struct perf_pmu *pmu_lookup(const char *name)
  309. {
  310. struct perf_pmu *pmu;
  311. LIST_HEAD(format);
  312. LIST_HEAD(aliases);
  313. __u32 type;
  314. /*
  315. * The pmu data we store & need consists of the pmu
  316. * type value and format definitions. Load both right
  317. * now.
  318. */
  319. if (pmu_format(name, &format))
  320. return NULL;
  321. if (pmu_aliases(name, &aliases))
  322. return NULL;
  323. if (pmu_type(name, &type))
  324. return NULL;
  325. pmu = zalloc(sizeof(*pmu));
  326. if (!pmu)
  327. return NULL;
  328. pmu->cpus = pmu_cpumask(name);
  329. INIT_LIST_HEAD(&pmu->format);
  330. INIT_LIST_HEAD(&pmu->aliases);
  331. list_splice(&format, &pmu->format);
  332. list_splice(&aliases, &pmu->aliases);
  333. pmu->name = strdup(name);
  334. pmu->type = type;
  335. list_add_tail(&pmu->list, &pmus);
  336. return pmu;
  337. }
  338. static struct perf_pmu *pmu_find(const char *name)
  339. {
  340. struct perf_pmu *pmu;
  341. list_for_each_entry(pmu, &pmus, list)
  342. if (!strcmp(pmu->name, name))
  343. return pmu;
  344. return NULL;
  345. }
  346. struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
  347. {
  348. /*
  349. * pmu iterator: If pmu is NULL, we start at the begin,
  350. * otherwise return the next pmu. Returns NULL on end.
  351. */
  352. if (!pmu) {
  353. pmu_read_sysfs();
  354. pmu = list_prepare_entry(pmu, &pmus, list);
  355. }
  356. list_for_each_entry_continue(pmu, &pmus, list)
  357. return pmu;
  358. return NULL;
  359. }
  360. struct perf_pmu *perf_pmu__find(const char *name)
  361. {
  362. struct perf_pmu *pmu;
  363. /*
  364. * Once PMU is loaded it stays in the list,
  365. * so we keep us from multiple reading/parsing
  366. * the pmu format definitions.
  367. */
  368. pmu = pmu_find(name);
  369. if (pmu)
  370. return pmu;
  371. return pmu_lookup(name);
  372. }
  373. static struct perf_pmu_format *
  374. pmu_find_format(struct list_head *formats, char *name)
  375. {
  376. struct perf_pmu_format *format;
  377. list_for_each_entry(format, formats, list)
  378. if (!strcmp(format->name, name))
  379. return format;
  380. return NULL;
  381. }
  382. /*
  383. * Returns value based on the format definition (format parameter)
  384. * and unformated value (value parameter).
  385. *
  386. * TODO maybe optimize a little ;)
  387. */
  388. static __u64 pmu_format_value(unsigned long *format, __u64 value)
  389. {
  390. unsigned long fbit, vbit;
  391. __u64 v = 0;
  392. for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
  393. if (!test_bit(fbit, format))
  394. continue;
  395. if (!(value & (1llu << vbit++)))
  396. continue;
  397. v |= (1llu << fbit);
  398. }
  399. return v;
  400. }
  401. /*
  402. * Setup one of config[12] attr members based on the
  403. * user input data - term parameter.
  404. */
  405. static int pmu_config_term(struct list_head *formats,
  406. struct perf_event_attr *attr,
  407. struct parse_events_term *term)
  408. {
  409. struct perf_pmu_format *format;
  410. __u64 *vp;
  411. /*
  412. * Support only for hardcoded and numnerial terms.
  413. * Hardcoded terms should be already in, so nothing
  414. * to be done for them.
  415. */
  416. if (parse_events__is_hardcoded_term(term))
  417. return 0;
  418. if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
  419. return -EINVAL;
  420. format = pmu_find_format(formats, term->config);
  421. if (!format)
  422. return -EINVAL;
  423. switch (format->value) {
  424. case PERF_PMU_FORMAT_VALUE_CONFIG:
  425. vp = &attr->config;
  426. break;
  427. case PERF_PMU_FORMAT_VALUE_CONFIG1:
  428. vp = &attr->config1;
  429. break;
  430. case PERF_PMU_FORMAT_VALUE_CONFIG2:
  431. vp = &attr->config2;
  432. break;
  433. default:
  434. return -EINVAL;
  435. }
  436. /*
  437. * XXX If we ever decide to go with string values for
  438. * non-hardcoded terms, here's the place to translate
  439. * them into value.
  440. */
  441. *vp |= pmu_format_value(format->bits, term->val.num);
  442. return 0;
  443. }
  444. int perf_pmu__config_terms(struct list_head *formats,
  445. struct perf_event_attr *attr,
  446. struct list_head *head_terms)
  447. {
  448. struct parse_events_term *term;
  449. list_for_each_entry(term, head_terms, list)
  450. if (pmu_config_term(formats, attr, term))
  451. return -EINVAL;
  452. return 0;
  453. }
  454. /*
  455. * Configures event's 'attr' parameter based on the:
  456. * 1) users input - specified in terms parameter
  457. * 2) pmu format definitions - specified by pmu parameter
  458. */
  459. int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
  460. struct list_head *head_terms)
  461. {
  462. attr->type = pmu->type;
  463. return perf_pmu__config_terms(&pmu->format, attr, head_terms);
  464. }
  465. static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
  466. struct parse_events_term *term)
  467. {
  468. struct perf_pmu_alias *alias;
  469. char *name;
  470. if (parse_events__is_hardcoded_term(term))
  471. return NULL;
  472. if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
  473. if (term->val.num != 1)
  474. return NULL;
  475. if (pmu_find_format(&pmu->format, term->config))
  476. return NULL;
  477. name = term->config;
  478. } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
  479. if (strcasecmp(term->config, "event"))
  480. return NULL;
  481. name = term->val.str;
  482. } else {
  483. return NULL;
  484. }
  485. list_for_each_entry(alias, &pmu->aliases, list) {
  486. if (!strcasecmp(alias->name, name))
  487. return alias;
  488. }
  489. return NULL;
  490. }
  491. static int check_unit_scale(struct perf_pmu_alias *alias,
  492. const char **unit, double *scale)
  493. {
  494. /*
  495. * Only one term in event definition can
  496. * define unit and scale, fail if there's
  497. * more than one.
  498. */
  499. if ((*unit && alias->unit) ||
  500. (*scale && alias->scale))
  501. return -EINVAL;
  502. if (alias->unit)
  503. *unit = alias->unit;
  504. if (alias->scale)
  505. *scale = alias->scale;
  506. return 0;
  507. }
  508. /*
  509. * Find alias in the terms list and replace it with the terms
  510. * defined for the alias
  511. */
  512. int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
  513. const char **unit, double *scale)
  514. {
  515. struct parse_events_term *term, *h;
  516. struct perf_pmu_alias *alias;
  517. int ret;
  518. /*
  519. * Mark unit and scale as not set
  520. * (different from default values, see below)
  521. */
  522. *unit = NULL;
  523. *scale = 0.0;
  524. list_for_each_entry_safe(term, h, head_terms, list) {
  525. alias = pmu_find_alias(pmu, term);
  526. if (!alias)
  527. continue;
  528. ret = pmu_alias_terms(alias, &term->list);
  529. if (ret)
  530. return ret;
  531. ret = check_unit_scale(alias, unit, scale);
  532. if (ret)
  533. return ret;
  534. list_del(&term->list);
  535. free(term);
  536. }
  537. /*
  538. * if no unit or scale foundin aliases, then
  539. * set defaults as for evsel
  540. * unit cannot left to NULL
  541. */
  542. if (*unit == NULL)
  543. *unit = "";
  544. if (*scale == 0.0)
  545. *scale = 1.0;
  546. return 0;
  547. }
  548. int perf_pmu__new_format(struct list_head *list, char *name,
  549. int config, unsigned long *bits)
  550. {
  551. struct perf_pmu_format *format;
  552. format = zalloc(sizeof(*format));
  553. if (!format)
  554. return -ENOMEM;
  555. format->name = strdup(name);
  556. format->value = config;
  557. memcpy(format->bits, bits, sizeof(format->bits));
  558. list_add_tail(&format->list, list);
  559. return 0;
  560. }
  561. void perf_pmu__set_format(unsigned long *bits, long from, long to)
  562. {
  563. long b;
  564. if (!to)
  565. to = from;
  566. memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
  567. for (b = from; b <= to; b++)
  568. set_bit(b, bits);
  569. }
  570. static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
  571. struct perf_pmu_alias *alias)
  572. {
  573. snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
  574. return buf;
  575. }
  576. static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
  577. struct perf_pmu_alias *alias)
  578. {
  579. snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
  580. return buf;
  581. }
  582. static int cmp_string(const void *a, const void *b)
  583. {
  584. const char * const *as = a;
  585. const char * const *bs = b;
  586. return strcmp(*as, *bs);
  587. }
  588. void print_pmu_events(const char *event_glob, bool name_only)
  589. {
  590. struct perf_pmu *pmu;
  591. struct perf_pmu_alias *alias;
  592. char buf[1024];
  593. int printed = 0;
  594. int len, j;
  595. char **aliases;
  596. pmu = NULL;
  597. len = 0;
  598. while ((pmu = perf_pmu__scan(pmu)) != NULL)
  599. list_for_each_entry(alias, &pmu->aliases, list)
  600. len++;
  601. aliases = malloc(sizeof(char *) * len);
  602. if (!aliases)
  603. return;
  604. pmu = NULL;
  605. j = 0;
  606. while ((pmu = perf_pmu__scan(pmu)) != NULL)
  607. list_for_each_entry(alias, &pmu->aliases, list) {
  608. char *name = format_alias(buf, sizeof(buf), pmu, alias);
  609. bool is_cpu = !strcmp(pmu->name, "cpu");
  610. if (event_glob != NULL &&
  611. !(strglobmatch(name, event_glob) ||
  612. (!is_cpu && strglobmatch(alias->name,
  613. event_glob))))
  614. continue;
  615. aliases[j] = name;
  616. if (is_cpu && !name_only)
  617. aliases[j] = format_alias_or(buf, sizeof(buf),
  618. pmu, alias);
  619. aliases[j] = strdup(aliases[j]);
  620. j++;
  621. }
  622. len = j;
  623. qsort(aliases, len, sizeof(char *), cmp_string);
  624. for (j = 0; j < len; j++) {
  625. if (name_only) {
  626. printf("%s ", aliases[j]);
  627. continue;
  628. }
  629. printf(" %-50s [Kernel PMU event]\n", aliases[j]);
  630. zfree(&aliases[j]);
  631. printed++;
  632. }
  633. if (printed)
  634. printf("\n");
  635. free(aliases);
  636. }
  637. bool pmu_have_event(const char *pname, const char *name)
  638. {
  639. struct perf_pmu *pmu;
  640. struct perf_pmu_alias *alias;
  641. pmu = NULL;
  642. while ((pmu = perf_pmu__scan(pmu)) != NULL) {
  643. if (strcmp(pname, pmu->name))
  644. continue;
  645. list_for_each_entry(alias, &pmu->aliases, list)
  646. if (!strcmp(alias->name, name))
  647. return true;
  648. }
  649. return false;
  650. }