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