PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/liblgrp/common/lgrp.c

https://bitbucket.org/a3217055/illumos-2
C | 1187 lines | 657 code | 183 blank | 347 comment | 255 complexity | 2ebecb81835b993739015b4caf572143 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, AGPL-3.0, BSD-3-Clause, LGPL-2.0, 0BSD, BSD-2-Clause, BSD-3-Clause-No-Nuclear-License-2014, AGPL-1.0, GPL-2.0
  1. /*
  2. * CDDL HEADER START
  3. *
  4. * The contents of this file are subject to the terms of the
  5. * Common Development and Distribution License, Version 1.0 only
  6. * (the "License"). You may not use this file except in compliance
  7. * with the License.
  8. *
  9. * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10. * or http://www.opensolaris.org/os/licensing.
  11. * See the License for the specific language governing permissions
  12. * and limitations under the License.
  13. *
  14. * When distributing Covered Code, include this CDDL HEADER in each
  15. * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16. * If applicable, add the following below this CDDL HEADER, with the
  17. * fields enclosed by brackets "[]" replaced with your own identifying
  18. * information: Portions Copyright [yyyy] [name of copyright owner]
  19. *
  20. * CDDL HEADER END
  21. */
  22. /*
  23. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  24. * Use is subject to license terms.
  25. */
  26. #pragma ident "%Z%%M% %I% %E% SMI"
  27. /*
  28. * lgroup interface
  29. */
  30. #include <errno.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <strings.h>
  34. #include <unistd.h>
  35. #include <sys/bitmap.h>
  36. #include <sys/pset.h>
  37. #include <sys/types.h>
  38. #include <sys/lgrp_user.h>
  39. /*
  40. * Fast trap for getting home lgroup of current thread
  41. */
  42. extern lgrp_id_t _lgrp_home_fast(void);
  43. /*
  44. * lgroup system call
  45. */
  46. extern int _lgrpsys(int subcode, long arg, void *ap);
  47. static int lgrp_cpus_hier(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp,
  48. processorid_t **cpuids, uint_t *count);
  49. /*
  50. * Get generation ID of lgroup hierarchy given view
  51. * which changes whenever the hierarchy changes (eg. DR or pset contents
  52. * change for caller's view)
  53. */
  54. static lgrp_gen_t
  55. lgrp_generation(lgrp_view_t view)
  56. {
  57. return (_lgrpsys(LGRP_SYS_GENERATION, view, NULL));
  58. }
  59. /*
  60. * Get supported revision number of lgroup interface
  61. */
  62. int
  63. lgrp_version(int version)
  64. {
  65. return (_lgrpsys(LGRP_SYS_VERSION, version, NULL));
  66. }
  67. /*
  68. * Get affinity for given lgroup
  69. */
  70. lgrp_affinity_t
  71. lgrp_affinity_get(idtype_t idtype, id_t id, lgrp_id_t lgrp)
  72. {
  73. lgrp_affinity_args_t args;
  74. args.idtype = idtype;
  75. args.id = id;
  76. args.lgrp = lgrp;
  77. return (_lgrpsys(LGRP_SYS_AFFINITY_GET, 0, (void *)&args));
  78. }
  79. /*
  80. * Set affinity for given lgroup
  81. */
  82. int
  83. lgrp_affinity_set(idtype_t idtype, id_t id, lgrp_id_t lgrp,
  84. lgrp_affinity_t aff)
  85. {
  86. lgrp_affinity_args_t args;
  87. args.idtype = idtype;
  88. args.id = id;
  89. args.lgrp = lgrp;
  90. args.aff = aff;
  91. return (_lgrpsys(LGRP_SYS_AFFINITY_SET, 0, (void *)&args));
  92. }
  93. /*
  94. * Get home lgroup for given process or thread
  95. */
  96. lgrp_id_t
  97. lgrp_home(idtype_t idtype, id_t id)
  98. {
  99. /*
  100. * Use fast trap to get home lgroup of current thread or process
  101. * Otherwise, use system call for other process or thread
  102. */
  103. if (id == P_MYID && (idtype == P_LWPID || idtype == P_PID))
  104. return (_lgrp_home_fast());
  105. else
  106. return (_lgrpsys(LGRP_SYS_HOME, idtype, (void *)(intptr_t)id));
  107. }
  108. /*
  109. * Get a snapshot of the lgroup hierarchy
  110. */
  111. static int
  112. lgrp_snapshot(void *buf, size_t bufsize)
  113. {
  114. return (_lgrpsys(LGRP_SYS_SNAPSHOT, bufsize, buf));
  115. }
  116. /*
  117. * Find any orphan lgroups without parents and make them be children of
  118. * root lgroup
  119. */
  120. static int
  121. parent_orphans(lgrp_snapshot_header_t *snap)
  122. {
  123. int i;
  124. lgrp_info_t *lgrp_info;
  125. int nlgrpsmax;
  126. int orphan;
  127. lgrp_info_t *root;
  128. ulong_t *parents;
  129. if (snap == NULL || snap->ss_info == NULL ||
  130. snap->ss_parents == NULL || snap->ss_root < 0 ||
  131. snap->ss_root >= snap->ss_nlgrps_max)
  132. return (-1);
  133. nlgrpsmax = snap->ss_nlgrps_max;
  134. root = &snap->ss_info[snap->ss_root];
  135. for (i = 0; i < nlgrpsmax; i++) {
  136. int j;
  137. /*
  138. * Skip root lgroup
  139. */
  140. if (i == snap->ss_root)
  141. continue;
  142. lgrp_info = &snap->ss_info[i];
  143. if (lgrp_info == NULL || lgrp_info->info_lgrpid == LGRP_NONE)
  144. continue;
  145. /*
  146. * Make sure parents bitmap is setup
  147. */
  148. if (lgrp_info->info_parents == NULL)
  149. lgrp_info->info_parents =
  150. (ulong_t *)((uintptr_t)snap->ss_parents +
  151. (i * BT_SIZEOFMAP(nlgrpsmax)));
  152. /*
  153. * Look for orphans (lgroups with no parents)
  154. */
  155. orphan = 1;
  156. parents = lgrp_info->info_parents;
  157. for (j = 0; j < BT_BITOUL(nlgrpsmax); j++)
  158. if (parents[j] != 0) {
  159. orphan = 0;
  160. break;
  161. }
  162. /*
  163. * Make root be parent of any orphans
  164. */
  165. if (orphan) {
  166. BT_SET(parents, root->info_lgrpid);
  167. if (root->info_children) {
  168. BT_SET(root->info_children, i);
  169. }
  170. }
  171. }
  172. return (0);
  173. }
  174. /*
  175. * Remove given lgroup from parent lgroup(s)
  176. */
  177. static void
  178. prune_child(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp)
  179. {
  180. int i;
  181. lgrp_info_t *lgrp_info;
  182. ulong_t *parents;
  183. if (snap == NULL || lgrp < 0 || lgrp > snap->ss_nlgrps_max)
  184. return;
  185. lgrp_info = &snap->ss_info[lgrp];
  186. parents = lgrp_info->info_parents;
  187. if (parents == NULL)
  188. return;
  189. /*
  190. * Update children of parents not to include given lgroup
  191. */
  192. for (i = 0; i < snap->ss_nlgrps_max; i++) {
  193. if (BT_TEST(parents, i)) {
  194. lgrp_info = &snap->ss_info[i];
  195. BT_CLEAR(lgrp_info->info_children, lgrp);
  196. }
  197. }
  198. }
  199. /*
  200. * Prune any CPUs not in given array from specified lgroup
  201. */
  202. static void
  203. prune_cpus(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp, processorid_t *cpus,
  204. int ncpus)
  205. {
  206. int count;
  207. int i;
  208. int j;
  209. int k;
  210. lgrp_info_t *lgrp_info;
  211. uint_t lgrp_ncpus;
  212. processorid_t *lgrp_cpus;
  213. if (snap == NULL || lgrp < 0 || lgrp > snap->ss_nlgrps_max)
  214. return;
  215. lgrp_info = &snap->ss_info[lgrp];
  216. /*
  217. * No CPUs to remove
  218. */
  219. if (ncpus == 0 || lgrp_info->info_ncpus == 0)
  220. return;
  221. /*
  222. * Remove all CPUs from lgroup
  223. */
  224. if (cpus == NULL && ncpus == -1) {
  225. lgrp_info->info_ncpus = 0;
  226. return;
  227. }
  228. /*
  229. * Remove any CPUs from lgroup not in given list of CPUs
  230. */
  231. lgrp_cpus = lgrp_info->info_cpuids;
  232. lgrp_ncpus = lgrp_info->info_ncpus;
  233. i = 0;
  234. for (count = 0; count < lgrp_ncpus; count++) {
  235. /*
  236. * Look for CPU in list
  237. */
  238. for (j = 0; j < ncpus; j++)
  239. if (lgrp_cpus[i] == cpus[j])
  240. break;
  241. /*
  242. * Go to next CPU if found this one in list
  243. */
  244. if (j < ncpus) {
  245. i++;
  246. continue;
  247. }
  248. /*
  249. * Remove this CPU and shift others into its place
  250. * and decrement number of CPUs
  251. */
  252. for (k = i + 1; k < lgrp_info->info_ncpus; k++)
  253. lgrp_cpus[k - 1] = lgrp_cpus[k];
  254. lgrp_cpus[k - 1] = -1;
  255. lgrp_info->info_ncpus--;
  256. }
  257. }
  258. /*
  259. * Prune lgroup hierarchy for caller's view
  260. */
  261. static int
  262. prune_tree(lgrp_snapshot_header_t *snap)
  263. {
  264. processorid_t *cpus;
  265. int i;
  266. lgrp_info_t *lgrp_info;
  267. lgrp_mem_size_t nbytes;
  268. uint_t ncpus;
  269. int nlgrps_max;
  270. if (snap == NULL || snap->ss_info == NULL)
  271. return (-1);
  272. /*
  273. * Get CPUs in caller's pset
  274. */
  275. if (pset_info(PS_MYID, NULL, &ncpus, NULL) == -1)
  276. return (-1);
  277. cpus = NULL;
  278. if (ncpus > 0) {
  279. cpus = malloc(ncpus * sizeof (processorid_t));
  280. if (pset_info(PS_MYID, NULL, &ncpus, cpus) == -1) {
  281. free(cpus);
  282. return (-1);
  283. }
  284. }
  285. /*
  286. * Remove any CPUs not in caller's pset from lgroup hierarchy
  287. */
  288. nlgrps_max = snap->ss_nlgrps_max;
  289. for (i = 0; i < nlgrps_max; i++) {
  290. lgrp_info = &snap->ss_info[i];
  291. if (BT_TEST(snap->ss_lgrpset, i))
  292. prune_cpus(snap, i, cpus, ncpus);
  293. else if (lgrp_info->info_lgrpid != LGRP_NONE)
  294. prune_cpus(snap, i, NULL, -1);
  295. }
  296. if (ncpus > 0)
  297. free(cpus);
  298. /*
  299. * Change lgroup bitmask from just reflecting lgroups overlapping
  300. * caller's pset to all lgroups available to caller, starting by
  301. * filling in all lgroups and then removing any empty ones below
  302. */
  303. for (i = 0; i < nlgrps_max; i++) {
  304. lgrp_info = &snap->ss_info[i];
  305. if (lgrp_info->info_lgrpid == LGRP_NONE)
  306. continue;
  307. BT_SET(snap->ss_lgrpset, i);
  308. }
  309. /*
  310. * Remove empty lgroups from lgroup hierarchy, removing it from its
  311. * parents and decrementing nlgrps
  312. */
  313. for (i = 0; i < nlgrps_max; i++) {
  314. lgrp_info = &snap->ss_info[i];
  315. if (lgrp_info->info_lgrpid == LGRP_NONE)
  316. continue;
  317. ncpus = lgrp_cpus_hier(snap, i, NULL, NULL);
  318. nbytes = lgrp_mem_size((lgrp_cookie_t)snap, i,
  319. LGRP_MEM_SZ_INSTALLED, LGRP_CONTENT_HIERARCHY);
  320. if (ncpus == 0 && nbytes == 0) {
  321. BT_CLEAR(snap->ss_lgrpset, i);
  322. prune_child(snap, i);
  323. snap->ss_nlgrps--;
  324. }
  325. }
  326. return (0);
  327. }
  328. /*
  329. * Initialize lgroup interface
  330. */
  331. lgrp_cookie_t
  332. lgrp_init(lgrp_view_t view)
  333. {
  334. ssize_t bufsize;
  335. uint_t gen;
  336. int i;
  337. lgrp_snapshot_header_t *snap;
  338. /*
  339. * Check for legal view
  340. */
  341. if (view != LGRP_VIEW_OS && view != LGRP_VIEW_CALLER) {
  342. errno = EINVAL;
  343. return (LGRP_COOKIE_NONE);
  344. }
  345. /*
  346. * Try to take a consistent snapshot of lgroup hierarchy
  347. */
  348. snap = NULL;
  349. while (snap == NULL) {
  350. /*
  351. * Get lgroup generation number before taking snapshot
  352. */
  353. gen = lgrp_generation(view);
  354. /*
  355. * Get size of buffer needed for snapshot
  356. */
  357. bufsize = lgrp_snapshot(NULL, 0);
  358. if (bufsize <= 0) {
  359. if (errno == ENOMEM)
  360. return (LGRP_COOKIE_NONE);
  361. snap = NULL;
  362. continue;
  363. }
  364. /*
  365. * Allocate buffer
  366. */
  367. snap = malloc(bufsize);
  368. if (snap == NULL)
  369. return (LGRP_COOKIE_NONE);
  370. bzero(snap, bufsize);
  371. /*
  372. * Take snapshot of lgroup hierarchy
  373. */
  374. bufsize = lgrp_snapshot(snap, bufsize);
  375. if (bufsize <= 0) {
  376. free(snap);
  377. if (errno == ENOMEM)
  378. return (LGRP_COOKIE_NONE);
  379. snap = NULL;
  380. continue;
  381. }
  382. /*
  383. * See whether lgroup generation number changed
  384. */
  385. if (gen == lgrp_generation(view))
  386. break;
  387. free(snap);
  388. snap = NULL;
  389. }
  390. /*
  391. * Remember generation number and view of this snapshot
  392. */
  393. snap->ss_gen = gen;
  394. snap->ss_view = view;
  395. /*
  396. * Keep caller's pset ID for caller's view
  397. */
  398. snap->ss_pset = 0;
  399. if (view == LGRP_VIEW_CALLER) {
  400. psetid_t pset;
  401. if (pset_bind(PS_QUERY, P_LWPID, P_MYID, &pset) == -1)
  402. return ((uintptr_t)-1);
  403. snap->ss_pset = pset;
  404. }
  405. /*
  406. * Find any orphan lgroups without parents and make them be children
  407. * of the root lgroup
  408. */
  409. if (snap->ss_levels > 1)
  410. (void) parent_orphans(snap);
  411. /*
  412. * Prune snapshot of lgroup hierarchy for caller's view
  413. */
  414. if (view == LGRP_VIEW_CALLER)
  415. (void) prune_tree(snap);
  416. else {
  417. /*
  418. * Change lgroup bitmask from just reflecting lgroups
  419. * overlapping caller's pset to all lgroups available
  420. */
  421. for (i = 0; i < snap->ss_nlgrps_max; i++) {
  422. lgrp_info_t *lgrp_info;
  423. lgrp_info = &snap->ss_info[i];
  424. if (lgrp_info->info_lgrpid == LGRP_NONE)
  425. continue;
  426. BT_SET(snap->ss_lgrpset, i);
  427. }
  428. }
  429. return ((uintptr_t)snap);
  430. }
  431. /*
  432. * Return whether given cookie is out-of-date (stale) or not
  433. */
  434. int
  435. lgrp_cookie_stale(lgrp_cookie_t cookie)
  436. {
  437. psetid_t pset;
  438. lgrp_snapshot_header_t *snap;
  439. /*
  440. * Check for bad cookie
  441. */
  442. snap = (lgrp_snapshot_header_t *)cookie;
  443. if (snap == NULL || snap->ss_magic != cookie) {
  444. errno = EINVAL;
  445. return (-1);
  446. }
  447. /*
  448. * Check generation number which changes when lgroup hierarchy changes
  449. * or pset contents change for caller's view
  450. */
  451. if (snap->ss_gen != lgrp_generation(snap->ss_view))
  452. return (1);
  453. /*
  454. * See whether pset binding has changed for caller's view
  455. */
  456. if (snap->ss_view == LGRP_VIEW_CALLER) {
  457. if (pset_bind(PS_QUERY, P_LWPID, P_MYID, &pset) == -1)
  458. return (-1);
  459. if (snap->ss_pset != pset)
  460. return (1);
  461. }
  462. return (0); /* cookie isn't stale */
  463. }
  464. /*
  465. * Get view of lgroup hierarchy from snapshot represented by given cookie
  466. */
  467. lgrp_view_t
  468. lgrp_view(lgrp_cookie_t cookie)
  469. {
  470. lgrp_snapshot_header_t *snap;
  471. snap = (lgrp_snapshot_header_t *)cookie;
  472. if (snap == NULL || snap->ss_magic != cookie) {
  473. errno = EINVAL;
  474. return (-1);
  475. }
  476. return (snap->ss_view);
  477. }
  478. /*
  479. * Get number of lgroups
  480. */
  481. int
  482. lgrp_nlgrps(lgrp_cookie_t cookie)
  483. {
  484. lgrp_snapshot_header_t *snap;
  485. snap = (lgrp_snapshot_header_t *)cookie;
  486. if (snap == NULL || snap->ss_magic != cookie) {
  487. errno = EINVAL;
  488. return (-1);
  489. }
  490. return (snap->ss_nlgrps);
  491. }
  492. /*
  493. * Return root lgroup ID
  494. */
  495. lgrp_id_t
  496. lgrp_root(lgrp_cookie_t cookie)
  497. {
  498. lgrp_snapshot_header_t *snap;
  499. snap = (lgrp_snapshot_header_t *)cookie;
  500. if (snap == NULL || snap->ss_magic != cookie) {
  501. errno = EINVAL;
  502. return (-1);
  503. }
  504. return (snap->ss_root);
  505. }
  506. /*
  507. * Get parent lgroups of given lgroup
  508. */
  509. int
  510. lgrp_parents(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *parents,
  511. uint_t count)
  512. {
  513. int i;
  514. ulong_t *lgrp_parents;
  515. lgrp_snapshot_header_t *snap;
  516. int nlgrps_max;
  517. int nparents;
  518. snap = (lgrp_snapshot_header_t *)cookie;
  519. /*
  520. * Check for valid arguments
  521. */
  522. if (snap == NULL || snap->ss_magic != cookie ||
  523. lgrp < 0 || lgrp == LGRP_NONE) {
  524. errno = EINVAL;
  525. return (-1);
  526. }
  527. /*
  528. * See whether given lgroup exists
  529. */
  530. nlgrps_max = snap->ss_nlgrps_max;
  531. if (lgrp >= nlgrps_max || !BT_TEST(snap->ss_lgrpset, lgrp)) {
  532. errno = ESRCH;
  533. return (-1);
  534. }
  535. /*
  536. * No parents, since given lgroup is root lgroup or
  537. * only one level in lgroup hierarchy (ie. SMP)
  538. */
  539. if (lgrp == snap->ss_root || snap->ss_levels == 1) {
  540. if (parents == NULL || count < 1)
  541. return (0);
  542. return (0);
  543. }
  544. /*
  545. * Make sure that parents exist
  546. */
  547. if (snap->ss_parents == NULL) {
  548. errno = ESRCH;
  549. return (-1);
  550. }
  551. /*
  552. * Given lgroup should have a parent
  553. */
  554. lgrp_parents = &snap->ss_parents[lgrp * BT_BITOUL(nlgrps_max)];
  555. if (lgrp_parents == NULL) {
  556. errno = ESRCH;
  557. return (-1);
  558. }
  559. /*
  560. * Check lgroup parents bitmask, fill in parents array, and return
  561. * number of parents
  562. */
  563. nparents = 0;
  564. for (i = 0; i < nlgrps_max; i++) {
  565. if (BT_TEST(lgrp_parents, i)) {
  566. if (parents != NULL && nparents < count) {
  567. parents[nparents] = i;
  568. }
  569. nparents++;
  570. }
  571. }
  572. return (nparents);
  573. }
  574. /*
  575. * Get children lgroups of given lgroup
  576. */
  577. int
  578. lgrp_children(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *children,
  579. uint_t count)
  580. {
  581. int i;
  582. ulong_t *lgrp_children;
  583. int nlgrps_max;
  584. int nchildren;
  585. lgrp_snapshot_header_t *snap;
  586. snap = (lgrp_snapshot_header_t *)cookie;
  587. /*
  588. * Check for valid arguments
  589. */
  590. if (snap == NULL || snap->ss_magic != cookie ||
  591. lgrp < 0 || lgrp == LGRP_NONE) {
  592. errno = EINVAL;
  593. return (-1);
  594. }
  595. /*
  596. * See whether given lgroup exists
  597. */
  598. nlgrps_max = snap->ss_nlgrps_max;
  599. if (lgrp >= nlgrps_max || !BT_TEST(snap->ss_lgrpset, lgrp)) {
  600. errno = ESRCH;
  601. return (-1);
  602. }
  603. /*
  604. * No children, since only one level in lgroup hierarchy (ie. SMP)
  605. */
  606. if (snap->ss_levels == 1) {
  607. if (children == NULL || count < 1)
  608. return (0);
  609. return (0);
  610. }
  611. /*
  612. * Make sure that children exist
  613. */
  614. if (snap->ss_children == NULL) {
  615. errno = ESRCH;
  616. return (-1);
  617. }
  618. /*
  619. * Given lgroup may not have any children
  620. */
  621. lgrp_children = &snap->ss_children[lgrp * BT_BITOUL(nlgrps_max)];
  622. if (lgrp_children == NULL)
  623. return (0);
  624. /*
  625. * Check lgroup children bitmask, fill in children array, and return
  626. * number of children
  627. */
  628. nchildren = 0;
  629. for (i = 0; i < nlgrps_max; i++) {
  630. if (BT_TEST(lgrp_children, i)) {
  631. if (children != NULL && nchildren < count)
  632. children[nchildren] = i;
  633. nchildren++;
  634. }
  635. }
  636. return (nchildren);
  637. }
  638. /*
  639. * Get all CPUs within given lgroup (hierarchy)
  640. */
  641. static int
  642. lgrp_cpus_hier(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp,
  643. processorid_t **cpuids, uint_t *count)
  644. {
  645. processorid_t *cpus;
  646. int i;
  647. int j;
  648. lgrp_info_t *lgrp_info;
  649. int ncpus;
  650. int nlgrps_max;
  651. ulong_t *rset;
  652. int total;
  653. /*
  654. * Get lgroup info
  655. */
  656. lgrp_info = &snap->ss_info[lgrp];
  657. if (lgrp_info == NULL) {
  658. errno = ESRCH;
  659. return (-1);
  660. }
  661. /*
  662. * Check whether given lgroup contains any lgroups with CPU resources
  663. */
  664. if (lgrp_info->info_rset == NULL)
  665. return (0);
  666. nlgrps_max = snap->ss_nlgrps_max;
  667. rset = &lgrp_info->info_rset[LGRP_RSRC_CPU * BT_BITOUL(nlgrps_max)];
  668. /*
  669. * Get all CPUs within this lgroup
  670. */
  671. total = 0;
  672. for (i = 0; i < nlgrps_max; i++) {
  673. if (!BT_TEST(rset, i))
  674. continue;
  675. lgrp_info = &snap->ss_info[i];
  676. /*
  677. * Get all CPUs within lgroup
  678. */
  679. cpus = lgrp_info->info_cpuids;
  680. ncpus = lgrp_info->info_ncpus;
  681. total += ncpus;
  682. /*
  683. * Copy as many CPU IDs into array that will fit
  684. * and decrement count and increment array pointer
  685. * as we go
  686. */
  687. if (cpuids && *cpuids && count) {
  688. for (j = 0; j < ncpus; j++) {
  689. if (*count) {
  690. **cpuids = cpus[j];
  691. (*cpuids)++;
  692. (*count)--;
  693. }
  694. }
  695. }
  696. }
  697. return (total);
  698. }
  699. /*
  700. * Get CPUs in given lgroup
  701. */
  702. int
  703. lgrp_cpus(lgrp_cookie_t cookie, lgrp_id_t lgrp, processorid_t *cpuids,
  704. uint_t count, lgrp_content_t content)
  705. {
  706. int i;
  707. processorid_t *cpus;
  708. lgrp_info_t *lgrp_info;
  709. int ncpus;
  710. lgrp_snapshot_header_t *snap;
  711. snap = (lgrp_snapshot_header_t *)cookie;
  712. /*
  713. * Check for valid arguments
  714. */
  715. if (snap == NULL || snap->ss_magic != cookie ||
  716. lgrp < 0 || lgrp == LGRP_NONE ||
  717. (content != LGRP_CONTENT_DIRECT &&
  718. content != LGRP_CONTENT_HIERARCHY)) {
  719. errno = EINVAL;
  720. return (-1);
  721. }
  722. /*
  723. * See whether given lgroup exists
  724. */
  725. if (lgrp >= snap->ss_nlgrps_max || snap->ss_info == NULL ||
  726. !BT_TEST(snap->ss_lgrpset, lgrp)) {
  727. errno = ESRCH;
  728. return (-1);
  729. }
  730. /*
  731. * Get lgroup info
  732. */
  733. lgrp_info = &snap->ss_info[lgrp];
  734. /*
  735. * Get contents of lgroup
  736. */
  737. switch (content) {
  738. case LGRP_CONTENT_DIRECT:
  739. /*
  740. * Get CPUs contained directly within given lgroup
  741. */
  742. cpus = lgrp_info->info_cpuids;
  743. ncpus = lgrp_info->info_ncpus;
  744. /*
  745. * No array to copy CPU IDs into,
  746. * so just return number of CPUs.
  747. */
  748. if (cpuids == NULL)
  749. return (ncpus);
  750. /*
  751. * Copy as many CPU IDs into array that will fit
  752. */
  753. for (i = 0; i < ncpus; i++)
  754. if (i < count)
  755. cpuids[i] = cpus[i];
  756. return (ncpus);
  757. case LGRP_CONTENT_ALL:
  758. return (lgrp_cpus_hier(snap, lgrp, &cpuids, &count));
  759. default:
  760. errno = EINVAL;
  761. return (-1);
  762. }
  763. }
  764. /*
  765. * Return physical memory size in pages for given lgroup
  766. */
  767. lgrp_mem_size_t
  768. lgrp_mem_size(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_mem_size_flag_t type,
  769. lgrp_content_t content)
  770. {
  771. int i;
  772. lgrp_info_t *lgrp_info;
  773. int nlgrps_max;
  774. int pgsz;
  775. ulong_t *rset;
  776. lgrp_mem_size_t size;
  777. lgrp_snapshot_header_t *snap;
  778. snap = (lgrp_snapshot_header_t *)cookie;
  779. /*
  780. * Check for valid arguments
  781. */
  782. if (snap == NULL || snap->ss_magic != cookie ||
  783. lgrp < 0 || lgrp == LGRP_NONE) {
  784. errno = EINVAL;
  785. return (-1);
  786. }
  787. /*
  788. * See whether given lgroup exists
  789. */
  790. nlgrps_max = snap->ss_nlgrps_max;
  791. if (lgrp >= nlgrps_max || snap->ss_info == NULL ||
  792. !BT_TEST(snap->ss_lgrpset, lgrp)) {
  793. errno = ESRCH;
  794. return (-1);
  795. }
  796. pgsz = getpagesize();
  797. /*
  798. * Get lgroup info
  799. */
  800. lgrp_info = &snap->ss_info[lgrp];
  801. switch (content) {
  802. case LGRP_CONTENT_DIRECT:
  803. /*
  804. * Get memory contained directly in this lgroup
  805. */
  806. switch (type) {
  807. case LGRP_MEM_SZ_FREE:
  808. size = (lgrp_mem_size_t)pgsz *
  809. lgrp_info->info_mem_free;
  810. return (size);
  811. case LGRP_MEM_SZ_INSTALLED:
  812. size = (lgrp_mem_size_t)pgsz *
  813. lgrp_info->info_mem_install;
  814. return (size);
  815. default:
  816. errno = EINVAL;
  817. return (-1);
  818. }
  819. case LGRP_CONTENT_ALL:
  820. /*
  821. * Get memory contained within this lgroup (and its children)
  822. */
  823. /*
  824. * Check whether given lgroup contains any lgroups with CPU
  825. * resources
  826. */
  827. if (lgrp_info->info_rset == NULL)
  828. return (0);
  829. rset = &lgrp_info->info_rset[LGRP_RSRC_MEM *
  830. BT_BITOUL(nlgrps_max)];
  831. /*
  832. * Add up memory in lgroup resources
  833. */
  834. size = 0;
  835. for (i = 0; i < nlgrps_max; i++) {
  836. if (!BT_TEST(rset, i))
  837. continue;
  838. lgrp_info = &snap->ss_info[i];
  839. switch (type) {
  840. case LGRP_MEM_SZ_FREE:
  841. size += (lgrp_mem_size_t)pgsz *
  842. lgrp_info->info_mem_free;
  843. break;
  844. case LGRP_MEM_SZ_INSTALLED:
  845. size += (lgrp_mem_size_t)pgsz *
  846. lgrp_info->info_mem_install;
  847. break;
  848. default:
  849. errno = EINVAL;
  850. return (-1);
  851. }
  852. }
  853. return (size);
  854. default:
  855. errno = EINVAL;
  856. return (-1);
  857. }
  858. }
  859. /*
  860. * Get resources for a particuliar lgroup
  861. */
  862. int
  863. lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *lgrps,
  864. uint_t count, lgrp_rsrc_t type)
  865. {
  866. int i;
  867. lgrp_info_t *lgrp_info;
  868. int nlgrps;
  869. int nlgrps_max;
  870. ulong_t *rset;
  871. lgrp_snapshot_header_t *snap;
  872. snap = (lgrp_snapshot_header_t *)cookie;
  873. /*
  874. * Check for valid arguments
  875. */
  876. if (snap == NULL || snap->ss_magic != cookie ||
  877. lgrp < 0 || lgrp == LGRP_NONE ||
  878. (type != LGRP_RSRC_CPU && type != LGRP_RSRC_MEM)) {
  879. errno = EINVAL;
  880. return (-1);
  881. }
  882. /*
  883. * See whether given lgroup exists
  884. */
  885. nlgrps_max = snap->ss_nlgrps_max;
  886. if (lgrp >= nlgrps_max || snap->ss_info == NULL ||
  887. !BT_TEST(snap->ss_lgrpset, lgrp)) {
  888. errno = ESRCH;
  889. return (-1);
  890. }
  891. /*
  892. * Get lgroup info
  893. */
  894. lgrp_info = &snap->ss_info[lgrp];
  895. /*
  896. * Count number lgroups contained within this lgroup and
  897. * copy as many lgroup IDs into array that will fit
  898. */
  899. rset = &lgrp_info->info_rset[type * BT_BITOUL(nlgrps_max)];
  900. nlgrps = 0;
  901. for (i = 0; i < snap->ss_nlgrps_max; i++)
  902. if (BT_TEST(rset, i)) {
  903. if (lgrps != NULL && nlgrps < count)
  904. lgrps[nlgrps] = i;
  905. nlgrps++;
  906. }
  907. return (nlgrps);
  908. }
  909. /*
  910. * Finish using lgroup interface
  911. */
  912. int
  913. lgrp_fini(lgrp_cookie_t cookie)
  914. {
  915. lgrp_snapshot_header_t *snap;
  916. snap = (lgrp_snapshot_header_t *)cookie;
  917. if (snap == NULL || snap->ss_magic != cookie) {
  918. errno = EINVAL;
  919. return (-1);
  920. }
  921. bzero(snap, snap->ss_size);
  922. free(snap);
  923. snap = NULL;
  924. return (0);
  925. }
  926. /*
  927. * Return latency between "from" and "to" lgroups
  928. *
  929. * This latency number can only be used for relative comparison
  930. * between lgroups on the running system, cannot be used across platforms,
  931. * and may not reflect the actual latency. It is platform and implementation
  932. * specific, so platform gets to decide its value. It would be nice if the
  933. * number was at least proportional to make comparisons more meaningful though.
  934. */
  935. int
  936. lgrp_latency(lgrp_id_t from, lgrp_id_t to)
  937. {
  938. lgrp_cookie_t cookie;
  939. int latency;
  940. cookie = lgrp_init(LGRP_VIEW_OS);
  941. latency = lgrp_latency_cookie(cookie, from, to, LGRP_LAT_CPU_TO_MEM);
  942. (void) lgrp_fini(cookie);
  943. return (latency);
  944. }
  945. /*
  946. * Return latency between "from" and "to" lgroups
  947. *
  948. * This latency number can only be used for relative comparison
  949. * between lgroups on the running system, cannot be used across platforms,
  950. * and may not reflect the actual latency. It is platform and implementation
  951. * specific, so platform gets to decide its value. It would be nice if the
  952. * number was at least proportional to make comparisons more meaningful though.
  953. */
  954. int
  955. lgrp_latency_cookie(lgrp_cookie_t cookie, lgrp_id_t from, lgrp_id_t to,
  956. lgrp_lat_between_t between)
  957. {
  958. lgrp_info_t *lgrp_info;
  959. lgrp_mem_size_t nbytes;
  960. int ncpus;
  961. int nlgrps_max;
  962. lgrp_snapshot_header_t *snap;
  963. snap = (lgrp_snapshot_header_t *)cookie;
  964. /*
  965. * Check for valid snapshot, lgroup, and between flag
  966. */
  967. if (snap == NULL || snap->ss_magic != cookie || from < 0 || to < 0 ||
  968. between != LGRP_LAT_CPU_TO_MEM) {
  969. errno = EINVAL;
  970. return (-1);
  971. }
  972. /*
  973. * Check whether lgroups exist
  974. */
  975. nlgrps_max = snap->ss_nlgrps_max;
  976. if (from >= nlgrps_max || to >= nlgrps_max) {
  977. errno = ESRCH;
  978. return (-1);
  979. }
  980. /*
  981. * Check whether "from" lgroup has any CPUs
  982. */
  983. ncpus = lgrp_cpus(cookie, from, NULL, 0, LGRP_CONTENT_HIERARCHY);
  984. if (ncpus <= 0) {
  985. if (ncpus == 0)
  986. errno = ESRCH;
  987. return (-1);
  988. }
  989. /*
  990. * Check whether "to" lgroup has any memory
  991. */
  992. nbytes = lgrp_mem_size(cookie, to, LGRP_MEM_SZ_INSTALLED,
  993. LGRP_CONTENT_HIERARCHY);
  994. if (nbytes <= 0) {
  995. if (nbytes == 0)
  996. errno = ESRCH;
  997. return (-1);
  998. }
  999. if (from == to) {
  1000. lgrp_info = &snap->ss_info[from];
  1001. return (lgrp_info->info_latency);
  1002. }
  1003. return (snap->ss_latencies[from][to]);
  1004. }