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