1use vstd::{
4 assert_seqs_equal, layout::size_of, prelude::*, set::Set, std_specs::iter::IteratorSpec,
5};
6use vstd_extra::{
7 bits::{group_u64_bit_algebra, lemma_u64_and_zero, u64_bit_is_set},
8 external::{
9 bits::{lemma_u64_set_bits_nonzero, u64_set_bits},
10 smallvec::{axiom_smallvec_from_iter_ensures, group_smallvec_models, smallvec_view},
11 },
12 ownership::Inv,
13};
14
15use super::cpu_count;
16use core::sync::atomic::{AtomicU64, Ordering};
17
18use smallvec::SmallVec;
19
20use super::{CpuId, num_cpus};
21use crate::const_assert;
22
23#[derive(Clone, Debug, Default)]
25#[verifier::allow(autoderive_clone_without_spec)]
26#[verus_verify]
27pub struct CpuSet {
28 bits: SmallVec<[InnerPart; NR_PARTS_NO_ALLOC]>,
30}
31
32type InnerPart = u64;
33
34#[verus_verify]
37const BITS_PER_PART: usize = 64;
38
39#[verus_verify]
40const NR_PARTS_NO_ALLOC: usize = 2;
41
42#[verus_spec(
43 returns part_idx_spec(cpu_id@),
44)]
45const fn part_idx(cpu_id: CpuId) -> usize {
46 cpu_id.as_usize() / BITS_PER_PART
47}
48
49#[verus_verify]
50#[verus_spec(
51 returns bit_idx_spec(cpu_id@),
52)]
53const fn bit_idx(cpu_id: CpuId) -> usize {
54 cpu_id.as_usize() % BITS_PER_PART
55}
56
57#[verus_verify]
58#[verifier::when_used_as_spec(parts_for_cpus_spec)]
59#[verus_spec(
60 returns parts_for_cpus_spec(num_cpus),
61)]
62const fn parts_for_cpus(num_cpus: usize) -> usize {
63 num_cpus.div_ceil(BITS_PER_PART)
64}
65
66verus! {
67
68broadcast use {
69 group_smallvec_models,
70 axiom_smallvec_from_iter_ensures,
71 vstd::std_specs::iter::group_iter_axioms,
72 lemma_u64_set_bits_nonzero,
73 group_u64_bit_algebra,
74 crate::cpu::axiom_cpu_count_bounds,
75 vstd::layout::layout_of_primitives,
76 vstd::set::group_set_lemmas,
77 vstd::set_lib::range_set_properties,
78};
79
80spec fn bit_at(seq: Seq<u64>, i: int) -> bool {
82 if 0 <= i < 64 * seq.len() {
83 u64_bit_is_set(seq[part_idx_spec(i) as int], i % 64)
84 } else {
85 false
86 }
87}
88
89impl View for CpuSet {
90 type V = Set<int>;
91
92 closed spec fn view(&self) -> Set<int> {
94 Set::range(0, cpu_count()).filter(|i: int| bit_at(smallvec_view(&self.bits), i))
95 }
96}
97
98impl CpuSet {
99 pub closed spec fn count_spec(&self) -> int {
101 count_set_bits(smallvec_view(&self.bits))
102 }
103
104 pub closed spec fn num_parts(&self) -> nat {
106 smallvec_view(&self.bits).len()
107 }
108}
109
110impl Inv for CpuSet {
111 closed spec fn inv(self) -> bool {
114 &&& smallvec_view(&self.bits).len() == parts_for_cpus_spec(cpu_count() as usize)
115 &&& forall|j: int|
116 #![trigger bit_at(smallvec_view(&self.bits), j)]
117 cpu_count() <= j < 64 * smallvec_view(&self.bits).len() ==> !bit_at(
118 smallvec_view(&self.bits),
119 j,
120 )
121 }
122}
123
124} #[verus_verify]
126impl CpuSet {
127 #[verus_spec(ret =>
129 ensures
130 ret@ == Set::range(0, cpu_count()),
131 ret.inv(),
132 )]
133 pub fn new_full() -> Self {
134 let mut ret = Self::with_capacity_val(num_cpus(), !0);
135 ret.clear_nonexistent_cpu_bits();
136 ret
137 }
138
139 #[verus_spec(ret =>
141 ensures
142 ret@ == Set::empty(),
143 ret.inv(),
144 )]
145 pub fn new_empty() -> Self {
146 let ret = Self::with_capacity_val(num_cpus(), 0);
147 proof! {
148 lemma_empty_bits_imply_empty_set(&ret);
149 assert forall|j: int|
150 cpu_count() <= j < 64 * smallvec_view(&ret.bits).len() implies !bit_at(
151 smallvec_view(&ret.bits),
152 j,
153 ) by {
154 lemma_u64_and_zero(1u64 << bit_idx_spec(j));
155 }
156 }
157 ret
158 }
159
160 #[verus_spec(
162 requires
163 self.inv(),
164 ensures
165 final(self)@ == old(self)@.insert(cpu_id@),
166 final(self).inv(),
167 )]
168 pub fn add(&mut self, cpu_id: CpuId) {
169 proof! {
170 use_type_invariant(&cpu_id);
171 }
172 let part_idx = part_idx(cpu_id);
173 let bit_idx = bit_idx(cpu_id);
174 if part_idx >= self.bits.len() {
175 self.bits.resize(part_idx + 1, 0);
176 }
177 self.bits[part_idx] |= 1 << bit_idx;
178 proof! {
179 let old_seq = smallvec_view(&old(self).bits);
180 let new_seq = smallvec_view(&self.bits);
181 let len = old_seq.len();
182 assert forall|j: int| cpu_count() <= j < 64 * len implies !bit_at(new_seq, j) by {
183 assert(bit_at(new_seq, j) == bit_at(old_seq, j));
184 }
185 }
186 }
187
188 #[verus_spec(
190 requires
191 self.inv(),
192 ensures
193 final(self)@ == old(self)@.remove(cpu_id@),
194 final(self).inv(),
195 )]
196 pub fn remove(&mut self, cpu_id: CpuId) {
197 let part_idx = part_idx(cpu_id);
198 let bit_idx = bit_idx(cpu_id);
199 if part_idx < self.bits.len() {
200 self.bits[part_idx] &= !(1 << bit_idx);
201 proof! {
202 let old_seq = smallvec_view(&old(self).bits);
203 let new_seq = smallvec_view(&self.bits);
204 assert forall|j: int| cpu_count() <= j < 64 * old_seq.len() implies !bit_at(
205 new_seq,
206 j,
207 ) by {
208 assert(bit_at(new_seq, j) == bit_at(old_seq, j));
209 }
210 }
211 }
212 }
213
214 #[verus_spec(ret =>
216 requires
217 self.inv(),
218 returns self@.contains(cpu_id@),
219 )]
220 pub fn contains(&self, cpu_id: CpuId) -> bool {
221 proof! {
222 use_type_invariant(&cpu_id);
223 }
224 let part_idx = part_idx(cpu_id);
225 let bit_idx = bit_idx(cpu_id);
226 part_idx < self.bits.len() && (self.bits[part_idx] & (1 << bit_idx)) != 0
227 }
228
229 #[verus_spec(
231 requires
232 self.inv(),
233 returns self.count_spec() as usize,
234 )]
235 pub fn count(&self) -> usize {
236 let mut count = 0usize;
244 let mut idx = 0usize;
245 #[verus_spec(
246 invariant
247 self.inv(),
248 idx <= smallvec_view(&self.bits).len(),
249 count == smallvec_view(&self.bits)[..idx].fold_left(
250 0,
251 |count: int, word: u64| count + u64_set_bits(word),
252 ),
253 count <= 64 * idx,
254 decreases
255 smallvec_view(&self.bits).len() - idx,
256 )]
257 while idx < self.bits.len() {
258 let part = self.bits[idx];
259 let part_count = part.count_ones() as usize;
260 proof! {
261 let seq = smallvec_view(&self.bits);
262 assert_seqs_equal!(
263 seq[..idx + 1].drop_last() == seq[..idx]
264 );
265 }
266 count += part_count;
267 idx += 1;
268 }
269 count
270 }
271
272 #[verus_spec(ret =>
274 requires
275 self.inv(),
276 returns self@ == Set::empty(),
277 )]
278 pub fn is_empty(&self) -> bool {
279 let ret = self.bits.iter().all(
283 #[verus_spec(ret: bool => ensures ret == (*part == 0u64))]
284 |part| *part == 0,
285 );
286 proof! {
287 let seq = smallvec_view(&self.bits);
288 if ret {
289 assert forall|i: int|
290 0 <= i < smallvec_view(&self.bits).len() implies
291 smallvec_view(&self.bits)[i] == 0u64 by {
292 assert(*seq.as_ref()[i] == seq[i]);
293 }
294 lemma_empty_bits_imply_empty_set(self);
295 } else {
296 let idx = choose|i: int| 0 <= i < seq.len() && seq[i] != 0u64;
297 lemma_u64_nonzero_has_set_bit(seq[idx]);
298 let b = choose|b: int| 0 <= b < 64 && #[trigger] u64_bit_is_set(seq[idx], b);
299 let j = 64 * idx + b;
300 assert(bit_at(seq, j));
301 assert(self@.contains(j));
302 }
303 }
304 ret
305 }
306
307 #[verus_spec(ret =>
309 requires
310 self.inv(),
311 returns self@ == Set::range(0, cpu_count()),
312 )]
313 pub fn is_full(&self) -> bool {
314 let num_cpus = num_cpus();
326 let mut idx = 0usize;
327 #[verus_spec(
328 invariant
329 self.inv(),
330 num_cpus == cpu_count(),
331 idx <= smallvec_view(&self.bits).len(),
332 forall|i: int|
333 #![trigger smallvec_view(&self.bits)[i]]
334 0 <= i < idx ==> smallvec_view(&self.bits)[i]
335 == full_set_word(
336 cpu_count(),
337 smallvec_view(&self.bits).len() as int,
338 i,
339 ),
340 decreases
341 smallvec_view(&self.bits).len() - idx,
342 )]
343 while idx < self.bits.len() {
344 let expected = if idx == self.bits.len() - 1 && num_cpus % BITS_PER_PART != 0 {
345 (1 << (num_cpus % BITS_PER_PART)) - 1
346 } else {
347 !0
348 };
349 if self.bits[idx] != expected {
350 proof! {
351 lemma_mismatched_word_imply_not_full_set(self, idx as int);
352 }
353 return false;
354 }
355 idx += 1;
356 }
357 proof! {
358 lemma_full_bits_imply_full_set(self);
359 }
360 true
361 }
362
363 #[verus_spec(
365 requires
366 self.inv(),
367 ensures
368 final(self)@ == Set::range(0, cpu_count()),
369 final(self).inv(),
370 )]
371 pub fn add_all(&mut self) {
372 self.bits.fill(!0);
373 self.clear_nonexistent_cpu_bits();
374 }
375
376 #[verus_spec(
378 requires
379 self.inv(),
380 ensures
381 final(self)@ == Set::empty(),
382 final(self).inv(),
383 )]
384 pub fn clear(&mut self) {
385 self.bits.fill(0);
386 proof! {
387 lemma_empty_bits_imply_empty_set(self);
388 assert forall|j: int|
389 cpu_count() <= j < 64 * smallvec_view(&self.bits).len() implies !bit_at(
390 smallvec_view(&self.bits),
391 j,
392 ) by {
393 lemma_u64_and_zero(1u64 << bit_idx_spec(j));
394 }
395 }
396 }
397
398 #[verus_spec(ret =>
402 requires
403 self.inv(),
404 ensures
405 IteratorSpec::obeys_prophetic_iter_laws(&ret),
406 IteratorSpec::decrease(&ret) is Some,
407 )]
408 pub fn iter(&self) -> impl Iterator<Item = CpuId> + '_ {
409 let end = self.bits.len() * BITS_PER_PART;
424 (0..end)
425 .filter(
426 #[verus_spec(ret: bool =>
427 requires
428 *id < end,
429 ensures
430 ret == bit_at(smallvec_view(&self.bits), *id as int),
431 )]
432 move |id| {
433 let part_idx = *id / BITS_PER_PART;
434 let bit_idx = *id % BITS_PER_PART;
435 (self.bits[part_idx] & (1 << bit_idx)) != 0
436 },
437 )
438 .map(
439 #[verus_spec(ret: CpuId =>
440 requires
441 bit_at(smallvec_view(&self.bits), id as int),
442 ensures
443 ret == CpuId(id as u32),
444 )]
445 move |id| CpuId(id as u32),
446 )
447 }
448
449 #[verus_spec(ret =>
451 requires
452 num_cpus == cpu_count(),
453 2 * parts_for_cpus_spec(num_cpus) * size_of::<u64>() <= isize::MAX,
454 ensures
455 smallvec_view(&ret.bits).len() == parts_for_cpus_spec(num_cpus),
456 forall|i: int|
457 #![trigger smallvec_view(&ret.bits)[i]]
458 0 <= i < smallvec_view(&ret.bits).len() ==> smallvec_view(&ret.bits)[i]
459 == val,
460 )]
461 fn with_capacity_val(num_cpus: usize, val: InnerPart) -> Self {
462 let num_parts = parts_for_cpus(num_cpus);
463 let mut bits = SmallVec::with_capacity(num_parts);
464 bits.resize(num_parts, val);
465 Self { bits }
466 }
467
468 #[verus_spec(
469 requires
470 smallvec_view(&self.bits).len() == parts_for_cpus_spec(cpu_count() as usize),
471 forall|j: int|
472 #![trigger bit_at(smallvec_view(&self.bits), j)]
473 0 <= j < cpu_count() ==> bit_at(smallvec_view(&self.bits), j),
474 ensures
475 final(self).inv(),
476 forall|j: int|
477 #![trigger bit_at(smallvec_view(&final(self).bits), j)]
478 0 <= j < cpu_count() ==> bit_at(smallvec_view(&final(self).bits), j),
479 )]
480 fn clear_nonexistent_cpu_bits(&mut self) {
481 let num_cpus = num_cpus();
482 if num_cpus % BITS_PER_PART != 0 {
483 let num_parts = parts_for_cpus(num_cpus);
484 self.bits[num_parts - 1] &= (1 << (num_cpus % BITS_PER_PART)) - 1;
485 proof! {
486 let n = cpu_count();
487 let old_seq = smallvec_view(&old(self).bits);
488 let new_seq = smallvec_view(&self.bits);
489 assert forall|j: int| 0 <= j < n implies
490 bit_at(new_seq, j) == bit_at(old_seq, j) by {}
491 }
492 }
493 }
494}
495
496#[derive(Debug)]
509#[verus_verify]
510pub struct AtomicCpuSet {
511 bits: SmallVec<[AtomicInnerPart; NR_PARTS_NO_ALLOC]>,
512}
513
514type AtomicInnerPart = AtomicU64;
515verus! {
518
519impl AtomicCpuSet {
520 pub closed spec fn num_parts(&self) -> nat {
522 smallvec_view(&self.bits).len()
523 }
524
525 #[verifier::type_invariant]
527 closed spec fn type_inv(self) -> bool {
528 Self::num_parts(&self) == parts_for_cpus_spec(cpu_count() as usize)
529 }
530}
531
532} #[verus_verify]
534impl AtomicCpuSet {
535 #[verus_spec(requires value.inv())]
537 pub fn new(value: CpuSet) -> Self {
538 let bits = value.bits.into_iter().map(AtomicU64::new).collect();
539 Self { bits }
540 }
541
542 #[verus_spec(ret =>
553 requires
554 ordering != Ordering::AcqRel,
555 ensures
556 ret.num_parts() == self.num_parts(),
557 )]
558 pub fn load(&self, ordering: Ordering) -> CpuSet {
559 let bits = self
560 .bits
561 .iter()
562 .map(|part| match ordering {
563 Ordering::Release => part.fetch_or(0, ordering),
564 _ => part.load(ordering),
565 })
566 .collect();
567 CpuSet { bits }
568 }
569
570 #[verus_spec(
577 requires
578 ordering != Ordering::Acquire,
579 ordering != Ordering::AcqRel,
580 )]
581 pub fn store(&self, value: &CpuSet, ordering: Ordering) {
582 #[verus_spec(
583 invariant
584 ordering != Ordering::Acquire,
585 ordering != Ordering::AcqRel,
586 )]
587 for (part, new_part) in self.bits.iter().zip(value.bits.iter()) {
588 part.store(*new_part, ordering);
589 }
590 }
591
592 pub fn add(&self, cpu_id: CpuId, ordering: Ordering) {
594 let part_idx = part_idx(cpu_id);
595 let bit_idx = bit_idx(cpu_id);
596 if part_idx < self.bits.len() {
597 self.bits[part_idx].fetch_or(1 << bit_idx, ordering);
598 }
599 }
600
601 pub fn remove(&self, cpu_id: CpuId, ordering: Ordering) {
603 let part_idx = part_idx(cpu_id);
604 let bit_idx = bit_idx(cpu_id);
605 if part_idx < self.bits.len() {
606 self.bits[part_idx].fetch_and(!(1 << bit_idx), ordering);
607 }
608 }
609
610 #[verus_spec(ret =>
612 requires
613 ordering != Ordering::Release,
614 ordering != Ordering::AcqRel,
615 ensures
616 cpu_id@ / 64 >= self.num_parts() ==> ret == false,
617 )]
618 pub fn contains(&self, cpu_id: CpuId, ordering: Ordering) -> bool {
619 let part_idx = part_idx(cpu_id);
620 let bit_idx = bit_idx(cpu_id);
621 part_idx < self.bits.len() && (self.bits[part_idx].load(ordering) & (1 << bit_idx)) != 0
622 }
623}
624
625verus! {
629
630spec fn parts_for_cpus_spec(n: usize) -> usize {
632 if n == 0 {
633 0
634 } else {
635 ((n + 63) / 64) as usize
636 }
637}
638
639spec fn part_idx_spec(i: int) -> usize {
641 (i / 64) as usize
642}
643
644spec fn bit_idx_spec(i: int) -> usize {
646 (i % 64) as usize
647}
648
649spec fn count_set_bits(seq: Seq<u64>) -> int {
651 seq.fold_left(0, |count: int, word: u64| count + u64_set_bits(word))
652}
653
654spec fn full_set_word(num_cpus: int, len: int, idx: int) -> u64 {
656 if idx == len - 1 && bit_idx_spec(num_cpus) != 0 {
657 ((1u64 << bit_idx_spec(num_cpus)) - 1) as u64
658 } else {
659 !0u64
660 }
661}
662
663proof fn lemma_u64_nonzero_has_set_bit_aux(word: u64, n: int)
664 requires
665 word != 0,
666 0 <= n <= 64,
667 word >> (n as u32) == 0,
668 ensures
669 exists|b: int| 0 <= b < n && #[trigger] u64_bit_is_set(word, b),
670 decreases n,
671{
672 if n == 0 {
673 assert(word >> (0u32) == word) by (bit_vector);
674 } else if !u64_bit_is_set(word, 0) {
675 let shifted = word >> 1u32;
676 assert(shifted != 0) by (bit_vector)
677 requires
678 shifted == word >> 1u32,
679 word != 0,
680 (word & (1u64 << 0usize)) == 0u64,
681 ;
682 let prev: int = n - 1;
683 let nu: u32 = n as u32;
684 let prevu: u32 = (n - 1) as u32;
685 assert(shifted >> prevu == word >> nu) by (bit_vector)
686 requires
687 shifted == word >> 1u32,
688 nu == prevu + 1,
689 nu <= 64,
690 ;
691 lemma_u64_nonzero_has_set_bit_aux(shifted, prev);
692 let b = choose|b: int| 0 <= b < n - 1 && #[trigger] u64_bit_is_set(shifted, b);
693 let bu: u32 = b as u32;
694 let next: u32 = (b + 1) as u32;
695 assert(u64_bit_is_set(word, b + 1)) by {
696 assert((word & (1u64 << next)) != 0) by (bit_vector)
697 requires
698 shifted == word >> 1u32,
699 (shifted & (1u64 << bu)) != 0,
700 next == bu + 1,
701 bu < 63,
702 ;
703 };
704 }
705}
706
707proof fn lemma_u64_nonzero_has_set_bit(word: u64)
708 requires
709 word != 0,
710 ensures
711 exists|b: int| 0 <= b < 64 && #[trigger] u64_bit_is_set(word, b),
712{
713 assert(word >> 64u32 == 0) by (bit_vector);
714 lemma_u64_nonzero_has_set_bit_aux(word, 64);
715}
716
717proof fn lemma_empty_bits_imply_empty_set(set: &CpuSet)
719 requires
720 smallvec_view(&set.bits).all(|w: u64| w == 0u64),
721 ensures
722 set@ == Set::empty(),
723{
724 let seq = smallvec_view(&set.bits);
725 assert forall|k: int| 0 <= k < seq.len() implies seq[k] == 0u64 by {
726 let p = |w: u64| w == 0u64;
727 assert(p(seq[k]));
728 }
729 assert forall|j: int| !set@.contains(j) by {
730 if 0 <= j < cpu_count() && j < 64 * seq.len() {
731 lemma_u64_and_zero(1u64 << bit_idx_spec(j));
732 }
733 }
734}
735
736proof fn lemma_full_bits_imply_full_set(set: &CpuSet)
738 requires
739 set.inv(),
740 forall|i: int|
741 #![trigger smallvec_view(&set.bits)[i]]
742 0 <= i < smallvec_view(&set.bits).len() ==> smallvec_view(&set.bits)[i]
743 == full_set_word(cpu_count(), smallvec_view(&set.bits).len() as int, i),
744 ensures
745 set@ == Set::range(0, cpu_count()),
746{
747 let seq = smallvec_view(&set.bits);
748 let n = cpu_count();
749 let len = seq.len();
750 assert forall|a: int|
751 #![trigger set@.contains(a)]
752 set@.contains(a) == Set::range(0, n).contains(a) by {
753 if 0 <= a < n {
754 let p = a / 64;
755 if a / 64 == len - 1 && n % 64 != 0 {
756 let mask = seq[p];
757 assert(!0u64 & mask == mask) by (bit_vector);
761 }
762 }
763 }
764}
765
766proof fn lemma_u64_distinct_bits_differ(x: u64, y: u64)
768 requires
769 x != y,
770 ensures
771 exists|b: int|
772 0 <= b < 64 && (#[trigger] (x & (1u64 << (b as usize)))) != (y & (1u64 << (
773 b as usize))),
774{
775 let diff: u64 = x ^ y;
776 assert(diff != 0u64) by (bit_vector)
777 requires
778 diff == x ^ y,
779 x != y,
780 ;
781 lemma_u64_nonzero_has_set_bit(diff);
782 let b = choose|b: int| 0 <= b < 64 && #[trigger] u64_bit_is_set(diff, b);
783 let bu: u32 = b as u32;
784 assert((x & (1u64 << bu)) != (y & (1u64 << bu))) by (bit_vector)
785 requires
786 (diff & (1u64 << bu)) != 0,
787 diff == x ^ y,
788 ;
789}
790
791proof fn lemma_u64_unit_bit_projection(x: u64, b: int)
793 requires
794 0 <= b < 64,
795 ensures
796 !u64_bit_is_set(x, b) || ((x & (1u64 << (b as usize))) == (1u64 << (b as usize))),
797{
798 let bu: u32 = b as u32;
799 assert((x & (1u64 << bu)) == 0u64 || (x & (1u64 << bu)) == (1u64 << bu)) by (bit_vector);
800}
801
802proof fn lemma_mismatched_word_imply_not_full_set(set: &CpuSet, p: int)
806 requires
807 set.inv(),
808 0 <= p < smallvec_view(&set.bits).len(),
809 smallvec_view(&set.bits)[p] != full_set_word(
810 cpu_count(),
811 smallvec_view(&set.bits).len() as int,
812 p,
813 ),
814 ensures
815 set@ != Set::range(0, cpu_count()),
816{
817 let seq = smallvec_view(&set.bits);
818 let n = cpu_count();
819 let len = seq.len() as int;
820 let k = n % 64;
821 let word = seq[p];
823 let expected = full_set_word(n, len, p);
824 lemma_u64_distinct_bits_differ(word, expected);
825 let b = choose|b: int|
826 0 <= b < 64 && (#[trigger] (word & (1u64 << (b as usize)))) != (expected & (1u64 << (
827 b as usize)));
828 lemma_u64_unit_bit_projection(word, b);
829 lemma_u64_unit_bit_projection(expected, b);
830 let j = 64 * p + b;
831 assert(set@.contains(j) == (0 <= j < n && bit_at(seq, j)));
832 if p == len - 1 && k != 0 {
833 if u64_bit_is_set(expected, b) {
834 if b >= k {
836 assert(!0u64 & expected == expected) by (bit_vector);
837 assert(false);
838 }
839 } else {
840 if b < k {
842 assert(!0u64 & expected == expected) by (bit_vector);
843 assert(false);
844 }
845 assert(bit_at(seq, j));
846 assert(false);
847 }
848 }
849}
850
851} #[cfg(ktest)]
853mod test {
854 use super::*;
855 use crate::{cpu::all_cpus, prelude::*};
856
857 #[ktest]
858 fn test_full_cpu_set_iter_is_all() {
859 let set = CpuSet::new_full();
860 let num_cpus = num_cpus();
861 let all_cpus = all_cpus().collect::<Vec<_>>();
862 let set_cpus = set.iter().collect::<Vec<_>>();
863
864 assert!(set_cpus.len() == num_cpus);
865 assert_eq!(set_cpus, all_cpus);
866 }
867
868 #[ktest]
869 fn test_full_cpu_set_contains_all() {
870 let set = CpuSet::new_full();
871 for cpu_id in all_cpus() {
872 assert!(set.contains(cpu_id));
873 }
874 }
875
876 #[ktest]
877 fn test_empty_cpu_set_iter_is_empty() {
878 let set = CpuSet::new_empty();
879 let set_cpus = set.iter().collect::<Vec<_>>();
880 assert!(set_cpus.is_empty());
881 }
882
883 #[ktest]
884 fn test_empty_cpu_set_contains_none() {
885 let set = CpuSet::new_empty();
886 for cpu_id in all_cpus() {
887 assert!(!set.contains(cpu_id));
888 }
889 }
890
891 #[ktest]
892 fn test_atomic_cpu_set_multiple_sizes() {
893 for test_num_cpus in [1usize, 3, 12, 64, 96, 99, 128, 256, 288, 1024] {
894 let test_all_iter = || (0..test_num_cpus).map(|id| CpuId(id as u32));
895
896 let set = CpuSet::with_capacity_val(test_num_cpus, 0);
897 let atomic_set = AtomicCpuSet::new(set);
898
899 for cpu_id in test_all_iter() {
900 assert!(!atomic_set.contains(cpu_id, Ordering::Relaxed));
901 if cpu_id.as_usize() % 3 == 0 {
902 atomic_set.add(cpu_id, Ordering::Relaxed);
903 }
904 }
905
906 let loaded = atomic_set.load(Ordering::Relaxed);
907 for cpu_id in loaded.iter() {
908 if cpu_id.as_usize() % 3 == 0 {
909 assert!(loaded.contains(cpu_id));
910 } else {
911 assert!(!loaded.contains(cpu_id));
912 }
913 }
914
915 atomic_set.store(
916 &CpuSet::with_capacity_val(test_num_cpus, 0),
917 Ordering::Relaxed,
918 );
919
920 for cpu_id in test_all_iter() {
921 assert!(!atomic_set.contains(cpu_id, Ordering::Relaxed));
922 atomic_set.add(cpu_id, Ordering::Relaxed);
923 }
924 }
925 }
926}